将请求范围数据传递给CDI中的异步方法



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方法,您都需要收集请求范围的数据,并在创建时将其传递给异步任务。

最新更新