2
@WebListener
public class AllRequestsWebListener implements ServletRequestListener {

    @Inject HttpRequestProducer producer;

    public void requestInitialized(ServletRequestEvent sre) {
    producer.requestInitialized(sre);
    }
}

...

@RequestScoped
public class HttpRequestProducer {
...
}

我不知道如何将 request-bean 作为方法参数注入,因此我猜想当 Request-bean 注入是 threadLocal 时它会正常工作。有人可以解释一下它是如何以线程安全的方式实现的吗?

4

2 回答 2

1

您在 bean 中注入的是代表真实交易的代理。代理将始终将调用转发到正确的 bean

于 2013-06-25T09:12:46.693 回答
0

基于直觉的答案

我相信它是线程安全的,因为请求范围是线程安全的(会话及以上不是,因为用户可以打开多个浏览器会话并使用相同的会话 ID)

我测试了它,虽然它是经验证据,但注入HttpRequestProducer的每个请求都会获得一个新实例。

请注意,requestInitializedandrequestDestroyed可以是(实际上是)不同的线程,因此如果您打算在两种方法上使用相同的注入对象,我将进一步调查。

规格支持的答案

困难的部分是在规格中为这种说法找到确凿的证据。

我查看了 CDI 规范,并不能很快找到确凿的证据证明 @RequestScoped 对象是线程安全的(例如,使用线程本地)但是我假设 @RequestScoped bean 使用与 Java EE 5 中的作用域 bean 相同的作用域: (见这里

在那里,这个条款很有趣:

控制对共享资源的并发访问 在多线程服务器中,可以同时访问共享资源。除了范围对象属性之外,共享资源还包括内存中的数据(例如实例或类变量)和外部对象,例如文件、数据库连接和网络连接。

并发访问可能在以下几种情况下出现:

  • 多个 Web 组件访问存储在 Web 上下文中的对象。

  • 多个 Web 组件访问存储在会话中的对象。

  • Web 组件中的多个线程访问实例变量。Web 容器通常会创建一个线程来处理每个请求。如果要确保 servlet 实例一次只处理一个请求,则 servlet 可以实现 SingleThreadModel 接口。如果一个 servlet 实现了这个接口,就可以保证在 servlet 的 service 方法中不会有两个线程同时执行。Web 容器可以通过同步对 servlet 的单个实例的访问,或通过维护 Web 组件实例池并将每个新请求分派到空闲实例来实现此保证。此接口不能防止由于 Web 组件访问共享资源(例如静态类变量或外部对象)而导致的同步问题。此外,Servlet 2.

所以从理论上讲,似乎对象本身每个请求线程都会有一个实例,但是我找不到任何确凿的证据证明这一点是受支持的。

于 2013-06-25T15:49:18.597 回答