【发布时间】:2016-03-28 19:45:36
【问题描述】:
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。
预计“请求范围”的数据应该可以从请求范围内执行的任务中访问。应该使用像 InheritableThreadLocal 这样的东西来允许评估来自新线程的原始线程数据。
这是一个错误吗?可能是我做错了什么?如果是 - 将此类数据传播到异步调用的正确方法是什么?
提前致谢。
【问题讨论】:
-
此外,ApplicationScoped 中有一个 RequestScoped bean。您可能想改用
@Inject Instance<CurrentUserService> currentUserBean。 -
@Gimby,你是对的。新线程可能会比原来的线程寿命更长。如您所见,我已经使用 ContextService 代理包装了调用。我希望代理将提供所需的上下文信息。无论如何,如何解决问题?我需要从新线程访问请求数据。我能以某种方式通过吗?
-
@jpkrohling,谢谢。我试过但没有运气:(
-
您的
Service.getToken()方法基本上是同步的。它在未来调用get,这将阻塞直到未来已经实现。所以你所拥有的所有异步机器无论如何都不会完成任何事情。 -
@Steve C,这只是一个例子。
标签: java asynchronous cdi wildfly java-ee-7