将 CDI 与 AsyncResponse 和 ExecutorService 结合使用

Using CDI with AsyncResponse and ExecutorService

在将 CDI 添加到我们的应用程序之前,我创建了一个资源,该资源使用 @Suspended AsyncResponse 对象来为聊天客户端实现长轮询。我所做的是创建一个新的 newSingleThreadExecutor()submit 一个 Runnable 到它,在消息列表上使用 .wait(30000) 直到通知发送新消息。在该任务中,我使用了 HttpServletRequest,它是使用 @Context 获得的,一切都运行良好。

然而,一旦我们将 CDI 添加到我们的应用程序,甚至没有将资源 class 设为 bean(仅扫描带注释的 bean,我们没有给它任何范围注释)我得到了一个 运行由于非法状态异常,无法访问 Runnable 任务中的请求对象的时间异常:

Method threw 'java.lang.IllegalStateException' exception. Cannot evaluate com.sun.proxy.$Proxy74.toString()

我不太确定为什么会这样,但我知道它与 CDI 相关,因为它指的是代理对象。一种猜测是资源 class 本身已成为 CDI 作用域,并且无法从其他线程访问该作用域?我在某处读到手动启动的线程不受管理,因此无法访问任何范围相关的对象。然而,在实施 CDI 之前,这是如何工作的?

现在我认为我已经使用球衣的 @ManagedAsync 注释解决了这个问题(即释放线程服务请求 I/O 并让工作人员接管等待直到收到通知)整个方法是 运行 在内部球衣执行程序服务中。这个对吗?同样在那种情况下,是否需要 AsyncResponse 对象?

编辑: 我还没有解决这个问题。 @ManagedAsync 在资源 class 未定义为 CDI bean 时起作用。使其成为 @RequestScoped 之后,每当我尝试调用该方法时,我都会收到以下异常

org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped

我认为这是因为请求可以在异步线程完成之前结束,这意味着所有范围对象(如 HttpServletRequest)都将被销毁,因此我们将无法访问它们。有没有办法在 @RequestScoped bean 中使用 @ManagedAsync 并利用 @Context HttpServletRequest??

长话短说:

  1. 如何访问手动启动的线程中的上下文资源?
  2. 为什么在实现 CDI 之前我可以访问请求对象?
  3. 是否可以在 @RequestScoped cdi bean 中使用 @ManagedAsync

旧方法:

@GET
@Path("method")
public void method(@Context HttpServletRequest request, @Suspended AsyncResponse ar) {
  //request object was accessible here
  Executors.newSingleTHreadExecutor().submit(() -> {
    //request object was also accessible here but lost access after implementing CDI.
    Object o = foo.bar(request);
    ar.resume(Response.ok(o).build());
  });
}

当前无效的方法:

@GET
@Path("method")
@ManagedAsync
public void method(@Context HttpServletRequest request, @Suspended AsyncResponse ar) {
  Object o = foo.bar(request);
  ar.resume(Response.ok(o).build()); //Is there any point to this?
}

回答你的问题 - 没有。您不能使用异步和请求范围内的对象。 CDI 中缺少异步支持 - 另请参阅 https://issues.jboss.org/browse/CDI-452