一、背景
我自定义注解,在切面中实现动态数据源切换,但是目标方法中新开线程使用异步的方式执行,导致在切面中主线程切换数据源参数,无法在异步的目标方法中使用。
二、实现方式
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 {
@Override
public 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