问题描述
举个例子,在我们正常的调用中有如下的业务流程,在一下的示例中,远程调用我们都没有使用异步编排。执行完1,在执行2,接着执行3。三个调用使用的都是同一个线程。这样的情况不存在丢失上下文的情况。当然这样的缺点明显,所有的远程调用都是排队执行,效率低下。
我们看下面这种情况,为了提高我们的效率,在service中我们对远程调用进行一个异步编排,将远程调用放在我们的线程池中,由不同的线程来执行,此时每个线程在远程调用时共享的数据都是在自己线程的Intercepter中,不同的线程当然都有属于自己的Intercepter。
简单来说就是我们主线程来到我们service方法中后,发现我们开启了异步任务编排,就会调用我们的线程池帮助我们创建几个子线程,而我们的各种数据都存在与主线程的ThreadLocal中,子线程中没有这些数据。所以在子线程执行远程调用时会抛出异常,上下文丢失。
解决如下:使用RequestContextHolder对象中的getRequestAttributes()方法得到原来主线程中的数据,然后在每个异步任务执行之前使用RequestContextHolder对象的setRequestAttributes()方法将主线程中的数据共享给子线程,使每个线程在执行异步任务时所携带的数据一致
public void tt(){
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
CompletableFuture<Void> AFuture = CompletableFuture.runAsync(() -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
FeginService.A();
}, executor);
CompletableFuture<Void> BFuture = CompletableFuture.runAsync(() -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
FeginService.B();
}, executor);
CompletableFuture<Void> CFuture = CompletableFuture.runAsync(() -> {
RequestContextHolder.setRequestAttributes(requestAttributes);
FeginService.C();
}, executor);
}