Java EE 7应用程序在Wildfly 9.0.2.Final上运行。从@Asynchronous方法中访问请求范围数据存在问题。
在Web过滤器数据(例如令牌)中设置为RequestScoped CDI bean。稍后我们想要访问这些数据。如果我们在一个线程中工作,一切正常。但如果需要异步运行代码,则会出现问题。 CDI注入空bean并且请求数据丢失。
以下是示例:
@RequestScoped
public class CurrentUserService implements Serializable {
public String token;
}
@Stateless
public class Service {
@Inject
private RestClient client;
@Resource
private ManagedExecutorService executorService;
@Resource
private ContextService contextService;
@Asynchronous
private <T> Future<T> getFuture(Supplier<T> supplier) {
Callable<T> task = supplier::get;
Callable<T> callable = contextService.createContextualProxy(task, Callable.class);
return executorService.submit(callable);
}
public String getToken() throws Exception {
return getFuture(client::getToken).get();
}
}
@ApplicationScoped
public class RestClient {
@Inject
private CurrentUserService currentUserBean;
public String getToken() {
return currentUserBean.token;
}
}
在给定的示例中,我们希望从异步Service.getToken方法访问当前用户令牌(CurrentUserService#token)。结果我们将收到null。
预计&#39;请求范围&#39;应该可以从请求范围内执行的任务访问数据。应该使用类似InheritableThreadLocal的东西来评估来自新线程的原始线程数据。
这是一个错误吗?可能是我做错了什么?如果是 - 将这些数据传播到异步调用的正确方法是什么?
提前致谢。
答案 0 :(得分:4)
根据Java EE Concurrency Utilities规范的§2.3.2.1,您不应该尝试这样做:
- 在提交组件的生命周期之后,提交给ExecutorService的托管实例的任务可能仍在运行。因此,不建议将范围为
@RequestScoped
,@SessionScoped
或@ConversationScoped
的CDI bean用作任务,因为无法保证任务在CDI上下文被销毁之前完成。
您需要收集请求范围的数据,并在创建它时将其传递给异步任务,无论是使用并发实用程序还是@Asynchronous方法。