为什么要使用无状态会话Bean?

7
我在阅读关于无状态会话bean的内容时,不太能理解它的用途。
以下是来自Sun教程的摘录:
“..由于无状态会话bean可以支持多个客户端,因此它们可以为需要大量客户端的应用程序提供更好的可扩展性。”
无状态会话bean被用在哪里?什么样的应用程序会使用它?
在“无状态会话bean”出现之前,有哪些机制用于在类似的情况下支持多个客户端?
请问有人可以提供一些详细信息吗?
谢谢!
6个回答

6

说实话,很难找到任何合理的 SLSB 使用场景。由于它们不保存任何状态(正如名称所示),它们应该天生就是线程安全的,即使容器对它们进行了池化。

另一方面,由于它们保证是线程安全的(多亏了池化),因此很容易将它们用作安全的临时存储,无需同步或线程安全集合。但是请考虑以下伪代码:

@Stateless
public class Slsb {
  private int counter;

  public void increment() {
    ++counter;
  }

  public int getCounter() {
    return counter;
  }
}

客户端:

@Resource
private Slsb slsb;

public void clientMethod() {
  slsb.increment();
  slsb.increment();
  slsb.getCounter();  //???
}

这段代码(尽管有些粗俗)非常好,不需要例如AtomicInteger之类的东西。

你期望什么结果?实际上,任何非负值都是可能的……任何对slsb的调用都可能由Slsb的不同实例提供服务,同时您(先前使用的)实例可能已被用于为不同的客户提供服务。结论:在SLSB中存储状态是错误的,但出于某种原因,SLSB被池化以避免线程问题(?!)。个人而言,我更喜欢单例服务(类似于Spring),从未理解过SLSB的想法。是的,我知道EJB 3.1中的单例EJB。


1
不是所有的都是线程安全的(感谢池化技术),例如参见EJB 3.1规范4.3.10.2无状态会话Bean:“由于无状态会话Bean实例通常被池化...”只是“通常被池化”。Wildfly 8-9默认情况下不会池化SLSB,但Wildfly 10会。 - Vsevolod Golovanov

5
使用EJB 3.0后,我认为无状态会话Bean存在是为了完善企业Bean架构。它们确实可以设置一个Facade以供其他业务逻辑使用。通常人们认为SLSB是线程安全的,但这种说法至少是误导性的。当它们的代码路径包括调用非线程安全代码(例如共享的非线程安全缓存)时,它们绝对不是线程安全的。 SLSLB提供的唯一保证是单个SLSB实例最多只被一个线程同时使用。这基本上归结为SLSB具有同步方法访问,并且将有多个实例来服务客户端调用。但是,如果SLSB方法从这些多个实例中调用来自共享的非线程安全类的代码,仍然可能会造成混乱,并使涉及的SLSB非线程安全。
由于EE上下文(事务、安全资源等)已经绑定到线程上,因此我认为在EJB-only应用程序中使用Spring Singletons而不是SLSB没有必要。它们与有状态会话bean相辅相成。
在我看来,他们选择使用SLSB和EJB 3.1的新锁并发设置是试图降低程序员的水平,让强大的容器满足你的需求。自己做个好事,去阅读《Java Concurrency in Practice》并开始使用单例模式结合基本Java线程并发构造(如同步、易失性变量、并发集合等)。

3
与大多数答案所说的相反,状态无关乎类本身的线程安全性。这绝对不是@Stateless的主要目标。开发者仍然负责确保代表@Stateless EJB的类没有声明任何实例变量(即没有状态)。容器不负责那部分。基本上,开发者必须说“嘿,容器,这是一个无状态业务服务类,我会用@Stateless进行注释,以便您可以将其用作无状态EJB”,而不是反过来。
如果需要状态,则使用@Stateful,每次客户端获取它时都会重新创建(因此,如果客户端是例如视图范围的JSF托管bean,则EJB将随着该bean的存在而存在,或者如果客户端是例如会话范围的CDI托管bean,则EJB将随着该bean的存在而存在,等等)。或者,使用@Singleton,它基本上是应用程序范围的并且实际上是线程锁定的。
无状态和池化与事务的线程安全性有更多关系。您可能已经知道,一个@Stateless上的单个方法调用默认计为一个完整的事务。然而,该事务反过来需要在特定EJB实例上进行线程锁定,因为所有敏感的前处理和后处理工作都需要。因此,EJB基本上可以阻止所有其他客户端想要调用相同方法直到事务提交。这正是它们按需克隆和池化的原因。
请注意,@Singleton不是池化的,并且默认情况下实际上是线程锁定的。现在您应该明白,当(滥用)作为“无状态EJB”时,@Singleton默认情况下绝对不比@Stateless更快。另请参见Java EE 7教程“管理单例会话bean中的并发访问”
另请参见:

2

首先,无状态会话Bean(SLSB)是一种服务器端技术 - 比如你不会在Swing代码中使用它们。

但是,它们例如被用作许多连接到中央服务器的客户端的“Facade”。SLSB包含业务逻辑,可以调用数据库等操作。

由于SLSB可以进行池化,因此您不需要为每个客户端创建一个SLSB,而只需要为每个同时存在的客户端创建一个。当SLSB未被使用时,它将被放回池中,以便下一个客户端使用。

由于SLSB“托管”在容器中,因此它们是线程安全的,并且容器会为您处理大量重要的工作:事务、安全性、资源注入等等。


1
无状态对象将使您与客户端松散耦合,因此可以轻松扩展。无状态会话Bean(SLB)是服务器端(EJB)组件,用于抽象业务逻辑。由于这种无状态性质,您可以轻松地将SLB部署在不运行在同一JVM之上的不同容器中。根据您的要求,您可以有一个或多个容器运行这些bean。

1

从非EJB技术特定的角度来看,无状态会话Bean是基础设施代码,显然不持有任何状态,但传递具有状态的对象。状态可以由您的有状态会话Bean或其他实现中的域POJO持有,而不是在EJB之外。如上所述,它是您业务层的入口点或门面。

在Java Web应用程序中,您可以按层设计,例如控制器、服务类(SLSB或仅为普通Java接口),然后是DAO或其他调用数据库/后端的内容。

EJB可以自动处理一些样板文件,例如事务、安全性等。


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