将 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
??
长话短说:
- 如何访问手动启动的线程中的上下文资源?
- 为什么在实现 CDI 之前我可以访问请求对象?
- 是否可以在
@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
在将 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
??
长话短说:
- 如何访问手动启动的线程中的上下文资源?
- 为什么在实现 CDI 之前我可以访问请求对象?
- 是否可以在
@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