将CDI与AsyncResponse和ExecutorService一起使用

时间:2016-01-14 10:33:58

标签: java multithreading scope jax-rs cdi

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

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

  

方法抛出'java.lang.IllegalStateException'异常。无法评估com.sun.proxy。$ Proxy74.toString()

我不确定为什么会发生这种情况,但我知道它与CDI有关,因为它引用了代理对象。一个猜测是资源类本身已成为CDI作用域,并且无法从不同的线程访问该作用域?我在某处读到手动启动的线程不受管理,因此无法访问任何与范围相关的对象。但是,在CDI实施之前,这是如何使用的?

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

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

  

org.jboss.weld.context.ContextNotActiveException:WELD-001303:范围类型javax.enterprise.context.RequestScoped没有活动的上下文

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

TL; DR:

  1. 如何在手动启动的线程中访问上下文资源?
  2. 为什么在实施CDI之前我有权访问请求对象?
  3. 是否可以在@Context HttpServletRequest cdi bean中使用@ManagedAsync
  4. 旧方法:

    @RequestScoped

    目前的非工作方法:

    @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());
      });
    }
    

1 个答案:

答案 0 :(得分:2)

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