将EJB作为实例变量注入到servlet中是否安全?

12
我们都知道在Web层中,存在可能会有一个给定的Servlet实例专为多个请求提供服务。这可能会导致实例变量中的线程问题。
我的问题是,在实例变量中使用@EJB注释将EJB注入到Servlet中是否安全?
我的第一反应是不安全的,因为假设同一个EJB实例将同时处理多个请求。看起来其他一些程序员也持有这种看法:不要将EJB注入到Servlets 但是,我是不是得出了错误的结论?显然,注入到Servlet中的是代理对象,在底层,容器是否真正为每个请求提供不同的实例并保持线程安全呢?正如这个论坛所建议的:可以将EJB注入到Servlets 似乎存在很多相互矛盾的观点。哪个是正确的?
4个回答

11
只要EJB是无状态的,就可以将其注入为Servlet实例变量,这样是安全的。您绝不能在Servlet中注入有状态的Bean。
您必须使EJB是无状态的,即不持有任何自身具有有状态值(如Persistence Context)的实例变量。如果需要使用persistence context,则必须在EJB方法中获取它的实例。您可以通过将PersistenceContextFactory作为EJB实例变量,并在EJB方法中从工厂获取实体管理器的实例来实现此操作。
由于PersistenceContextFactory是线程安全的,因此可以将其注入为实例变量。
只要您遵守上述规则,将Stateless Bean注入到Servlet中应该是线程安全的。

3
您的参考资料“不要将数据注入到servlet”并未提及ejbs或@ejb注释。它谈论的是诸如PersistenceContext这样的非线程安全对象。
根据EJB规范,您可以从各种远程客户端(包括servlets)访问ejbs(EJB 3.0规范(JSR-220)-第3.1节)。使用@EJB注释注入ejb是通过依赖注入(第3.4.1节)获取EJB接口的一种方法,这是查找JNDI命名空间中ejb对象的替代方法。因此,与获得的EJBs相关的@EJB注释没有什么特别之处。
因此,基于EJB 3.0规范,使用@EJB注释从servlets获取ejbs是一种标准做法。

这个答案在某种程度上是正确的,但它没有解决原帖作者的线程安全问题。我认为下面inferreddesign的答案应该是正确的。 - Laird Nelson
我猜使用 @Inject(CDI,JEE 6)注入的 EJB 也同样安全,不是吗? - marcus

1

这是一个混合包。

无状态会话Bean可以被注入并且是安全的。这是因为即使使用了存根的单个实例,容器也会对方法的访问进行序列化。

我认为inferreddesign所说的不是真的。无状态会话Bean是否使用持久性上下文并不重要。只有一个调用者会同时访问单个Bean实例,因此即使持久性上下文不是线程安全的,EJB也会防止对它的多次访问。可以将每个会话Bean方法视为已应用synchronized关键字。

我认为在Servlet中注入EJB的主要问题是性能。当多个请求在等待会话Bean方法执行时排队时,单个存根实例将成为主要争用区域。


存根将被同步,但我希望它会快速分派到池化的EJB之一来完成真正的工作。除非存根在整个调用期间都持有锁,这将是一个非常糟糕的实现选择... - marcus

0

我认为简单的答案是你不能保证它是安全的。

原因在于EJB规范中没有明确说明EJB主接口必须是线程安全的。规范仅概述了服务器端部分的行为。你可能会发现客户端骨架实际上是线程安全的,但你需要查看你正在使用的库如何实现它们。注释部分只会扩展成服务定位器,所以这并没有给你带来任何好处。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接