我在Spring Boot应用程序中使用Servlet 3控制器。该控制器调用最终发出3个HTTP请求的服务。
@GetMapping("/nbasync/c/**")
public CompletableFuture<String> nonBlockingAsyncCall() throws Exception {
CompletableFuture<String> result = service.call());
CompletableFuture<Void> result2 = service2.call();
CompletableFuture<Void> result3 = service3.call();
return result
.thenCombine(result2, this::keepFirst)
.thenCombine(result3, this::keepFirst);
}
每次拨出电话均使用RestTemplate
进行,并由ClientHttpRequestInterceptor
拦截。在这个ClientHttpRequestInterceptor
中,我需要一个(代理的)请求范围的bean(cf:How to enable request scope in async task executor和Runnable)。
如果我等待结果,这可以正常工作:
CompletableFuture.allOf(result, result2, result3).join();
return result.get();
在非阻塞方法中,它崩溃时出现以下异常:
java.util.concurrent.CompletionException:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.requestCookieHelper': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is
java.lang.IllegalStateException: Cannot ask for request attribute - request is not active anymore!
请参阅完整日志:https://gist.github.com/Skeebl/d0b19ebb9ab4d0d2a917203e4bd6fad5
似乎每次线程放开进程时,都会调用AbstractRequestAttributes.requestCompleted()
(两次)。此方法设置this.requestActive = false;
。虽然requestActive
为false,但您无法访问请求范围的bean。
拦截器和请求范围的bean简化了方法签名。有没有办法在处理异步请求时保留这些内容?