无状态会话Bean与Singleton会话Bean

时间:2010-01-06 15:27:32

标签: java singleton ejb-3.0 ejb stateless

Java EE 6 Tutorial说:

  

为了提高性能,如果它具有以下任何特征,您可以选择无状态会话bean:

     
      
  • bean的状态没有特定客户端的数据。
  •   
  • 在单个方法调用中,bean为所有客户端执行通用任务。例如,您可以使用无状态会话bean发送确认在线订单的电子邮件。
  •   
  • bean实现了一个Web服务。
  •   
     

Singleton会话bean适用于以下情况:

     
      
  • 需要在整个应用程序中共享状态。
  •   
  • 单个企业bean需要同时由多个线程访问。
  •   
  • 应用程序需要企业bean才能在应用程序启动和关闭时执行任务。
  •   
  • bean实现了一个Web服务。
  •   

但是如果使用什么:

  • 不必在整个应用程序中共享状态
  • 单个企业bean可以由多个线程同时访问
  • 无需启动或击落任务

比如说我有一个带有以下界面的登录服务:

public interface LoginService {
  boolean authenticate(String user, String password);
}

是否应该使用@Singleton或@Stateless进行注释?这一个和另一个有什么好处?如果LoginService需要注入一个EntityManager(可以同时使用),该怎么办?

添加:我正在考虑Spring服务bean的Java EE版本,它们是无状态的单例。如果我理解正确,Java EE对应的是@Stateless会话bean,并且@Singleton Beans用于在启动时配置应用程序或在关机时清理或保存应用程序范围的对象。这是对的吗?

8 个答案:

答案 0 :(得分:13)

我会选择无状态 - 服务器可以生成bean的许多实例并并行处理传入的请求。

Singleton听起来像是一个潜在的瓶颈 - 默认的@Lock值是@Lock(WRITE),但可以更改为@Lock(READ)用于bean或单个方法。

答案 1 :(得分:3)

根据ejb 3.1规范,第110页,第4.8.5节“Singleton Concurrency”:

  

在Singleton bean实例状态中存储不支持并发访问的Java EE对象(例如,实体管理器,有状态会话Bean引用)是合法的。但是,Bean Developer负责确保一次不能通过多个线程访问这些对象。

此外,根据hibernate entitymanager documentation

  

EntityManager是一种廉价的非线程安全对象,应该只使用一次,用于单个业务流程,单个工作单元,然后丢弃。

对我来说,这意味着你永远不应该将EntityManager注入到单例EJB中。只有在我需要在此类中实现的所有内容支持并发而不需要执行额外的锁定/同步时,我才会使用单独的EJB作为无状态EJB的替代。由于您或其他程序员迟早会从您的焦点中丢失此问题,我个人更喜欢不使用单例EJB,除了与启动相关的问题或可以作为自包含单元实现的功能 - 独立于其他bean。从这个意义上讲,将无状态EJB注入Singletons似乎并不可取。这样做会引发关于容器实际执行SLSB注入Singleton的时间点的问题?根据EJB 3.1规范,第4.8章,依赖注入在客户端访问单例bean实例之前完成。因此,单身人士显然会坚持SLSB的同一个实例,这似乎是隐含的单身,但似乎没有任何保证。至少我在规范中找不到任何东西,所以行为可能是不可预测的,或者在最好的情况下是容器特定的,这不是大多数人想要的。

因此,我只会将单身人士注入单身人士或单身人士进入SLSB,但反之亦然。对于将Singleton注入Singleton的情况,Spec为您提供了定义单例之间依赖关系的机会,以便容器可以按正确的顺序初始化它们(参见ejb 3.1规范,第4.8.1节关于@DependsOn注释)。

答案 2 :(得分:2)

@Stateless将允许您准备好在JVM中处理多个副本(尽可能多的内存和池大小),其中@Singleton在JVM中只有一个副本,即使单个副本也可以支持针对它运行的多个并发线程。

在性能方面@Singleton会更好,只要它使用的资源允许长时间运行访问。然而,在分布式环境中,有时会发生不好的事情,例数据库或网络链接可能会失败。

使用@Stateless bean,访问权限更短暂。此外,如果出现故障,它将重新生成并尝试建立与资源的新连接。如果在单例上出现类似的事情,那么单元就可以处理它而不需要重启应用程序,因为@PostConstruct只针对每个JVM调用一次。

在大多数情况下,我更喜欢容错性和性能,特别是在我无法控制的系统上。

答案 3 :(得分:1)

我认为Singleton在并发使用方面的性能不会比SLSB Pool差,它可能会更好。唯一的问题是如果你想在线程之间共享某些东西,你需要锁定它,这可能是一个很大的性能问题。因此,在这种情况下,SLSB池执行得更好,因为它不是100%单例,有更多实例,一个被锁定,另一个出现。无论如何,如果锁是由所有SLSB共享的某些资源,则池也不会有帮助。

简而言之,我认为单身人士比SLSB Pool更好,如果可以,你应该使用它。它也是Spring Beans的默认范围。

我不是JavaEE专家,这只是我的感觉,如果我错了,请纠正我。

答案 4 :(得分:0)

我认为你应该使用Singleton会话bean。因为登录服务应该是全局服务,并且不需要为具体用户或调用存储任何状态。

答案 5 :(得分:0)

如果您确定不在线程之间共享状态,那么Singleton就可以了,在这种情况下,您还应该使用@ConcurrencyManagement( ConcurrencyManagementType.BEAN )注释该类,这将允许多个线程在同一时间。

答案 6 :(得分:0)

如果您有任何资源在整个应用程序中保持不变,那么您应该选择Singleton。就像加载某些文件或参考数据中的一些数据一样,这些数据在整个应用程序生命周否则,去SLSB。 SLSB的缺点是会创建多个对象,因此会占用更多内存。

答案 7 :(得分:0)

我会这样回答:

“在整个应用程序中不需要共享状态”导致我使用无状态bean因为句子“为了提高性能,你可以选择无状态会话bean ......”。

考虑到“同时可以通过多个线程访问单个企业bean”,您必须使用单例。如果我做对了,在正确使用时甚至不可能同时访问无状态bean。

“启动或击落时无需执行任务”对我来说无关紧要。如果必须完成任务以正确设置bean,则必须通过@PostActivate方法调用它们。

我会在逻辑上总结您的问题,因为您要求进行并发访问,所以对@Singleton使用了什么。当然,您必须手动控制对任何其他资源(不是EJB)的访问的同步。