1.背景
今天测试报了个bug,订单完成时间是零时区,我感觉这是一个很简单的问题,分给新同事,后来新同事找不到原因,只能自己看了,结果不看不知道,一看看了一下午。
2.原因
看了一下午,感觉哪里都没有问题,越看越觉得没问题,啊哈哈哈,最后突然看到Fegin调用有一点不同。
最后经过验证@Async就是真凶,因为我们都是拿请求头的时区获取时间放入数据库,@Async会使请求头的数据消失,导致获取取不到时区。
3.解决办法
配置该类可以防止丢失
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
/*********************************************
* @ClassName: AsyncConfig
*
* @Author: Clare
*
* @Date: 2023/8/25 上午10:25
*
* @Description:
**********************************************/
@Configuration
public class AsyncConfig extends AsyncConfigurerSupport {
public class ContextAwareCallable<T> implements Callable<T> {
private Callable<T> task;
private RequestAttributes context;
public ContextAwareCallable(Callable<T> task, RequestAttributes context) {
this.task = task;
this.context = context;
}
@Override
public T call() throws Exception {
if (context != null) {
RequestContextHolder.setRequestAttributes(context);
}
try {
return task.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor {
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new ContextAwareCallable(task, RequestContextHolder.currentRequestAttributes()));
}
}
@Override
@Bean
public Executor getAsyncExecutor() {
return new ContextAwarePoolExecutor();
}
}