一、背景
我定义注解,在切面中实现动态数据源切换,但是目标方法中,使用新开线程,异步的方式执行,导致在切面中主线程切换数据源参数,无法在异步的目标方法中使用。
二、实现方式
1、创建UserUtils类。
public class UserUtils {private static final ThreadLocal<String> userLocal=new ThreadLocal<>();public static String getUserId(){return userLocal.get();}public static void setUserId(String userId){userLocal.set(userId);}public static void clear(){userLocal.remove();}
}
2、自定义TaskDecorator类型的类
public class CustomTaskDecorator implements TaskDecorator {@Overridepublic Runnable decorate(Runnable runnable) {// 获取主线程中的请求信息(我们的用户信息也放在里面)String robotId = UserUtils.getUserId();return () -> {try {// 将主线程的请求信息,设置到子线程中UserUtils.setUserId(robotId);// 执行子线程,这一步不要忘了runnable.run();} finally {// 线程结束,清空这些信息,否则可能造成内存泄漏UserUtils.clear();}};}
}
3、创建测试类,此方法依赖线程池,并需要在创建线程池类时,setTaskDecorator把自己的TaskDecorator类设置进去。
public class CreatePassword {public static void main(String[] args) {try{ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setTaskDecorator(new CustomTaskDecorator());executor.initialize();//InheritableThreadLocal存储ThreadLocal<String> username = new ThreadLocal<>();for (int i = 0; i < 2; i++) {UserUtils.setUserId("用户id:"+i);Thread.sleep(3000);CompletableFuture.runAsync(()-> System.out.println(UserUtils.getUserId()),executor);}}catch (Exception e){}}
}
4、测试结果
用户id:0
用户id:1