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#令牌)。因此,我们将收到null。
"请求范围"数据应该可以从请求范围内执行的任务中访问。应该使用类似InheritableThreadLocal的东西来允许评估来自新线程的原始线程数据。
是虫子吗?可能是我做错了什么?如果是,将这些数据传播到异步调用中的正确方式是什么?
提前谢谢。
根据Java EE并发实用程序规范的§2.3.2.1,您不应该尝试这样做:
- 提交到ExecutorService托管实例的任务可能在提交组件的生命周期之后仍在运行。因此,不建议将作用域为
@RequestScoped
、@SessionScoped
或@ConversationScoped
的CDI-beans用作任务,因为不能保证这些任务在CDI上下文被销毁之前完成
无论使用并发实用程序还是@asynchronous方法,您都需要收集请求范围的数据,并在创建时将其传递给异步任务。