业务层
J2EE 为在业务层上处理状态提供了内置的支持。与无状态会话 bean 一样,有状态会话 bean 也被映射到业务过程。两者之间的关键区别是:无状态 bean 及其数据在单个客户机请求的生命周期内存活,而有状态 bean 却维护与客户机的对话并且它们的数据跨多个请求持续存在。与 servlet 不同,有状态会话 bean 不需要任何特殊的对象,也不需要使用额外的接口来创建有状态连接。EJB 容器提供了所有有状态会话 bean 管理。对于 bean 而言,所有必要的工作就是在其部署描述符中将其声明为 stateful。
EJB 体系结构
从体系结构的观点看,有状态会话 bean 与其无状态的同类没有任何差别。两种类型的 bean 都可以很好地充当视图、控制器或模型;二者通常都可以实现虚包(Facade)模式或业务委派(Business Delegate)模式;二者都可以与多个客户机类型一起使用。有状态会话 bean 可以通过 servlet(或 JSP 文件)、帮助 servlet(或 JSP 文件)的 JavaBean 和另一个企业 bean 访问,或者直接通过 applet、Swing 应用程序或其它 Java 应用程序,或者甚至是使用 IIOP 协议的非 Java 客户机访问。
管理有状态 bean
正如以前阐述的,会话 bean 是最轻量级类型的企业 bean 类型。特别地,无状态会话 bean 可以方便地被容器合用,因为它们只需要维护每个请求的状态。
相反,有状态会话 bean 与容器资源并不那样友好。有状态会话 bean 的池不能象无状态 EJB 组件的池那样用来容纳任何客户机请求。有状态 bean 只能处理来自一个客户机的请求,直到该客户机释放其对那个特殊 bean 实例的控制。有状态会话 bean 消耗了容器的大量时间和内存。为了保存客户机调用之间的 bean 状态,容器必须将 bean 实例保存在活动内存中,或者临时将状态写到持久性存储(如文件系统或数据库)中。将状态分配到持久性存储中就是所谓的钝化(passivation)。当以前钝化的企业 bean 被再次请求时,容器通过从池中检索 bean,并且利用钝化前 bean 的持久性状态对它进行初始化,来激活它。下图阐明了有状态会话 bean 的钝化和激活:
决定将 bean 保存在内存中还是对它进行钝化,然后再激活它,这取决于各个供应商。尽管在释放容器资源方面钝化机制非常有帮助,但是在防止服务器崩溃以避免丢失有状态会话 bean 的活动状态方面却无能为力。尽管一些供应商提供了会话恢复功能以解决这个问题,但它不是标准的,因此依赖该功能会降低应用程序的可移植性。但是,别担心!EJB 规范确实定义了一个接口(javax.ejb.SessionSynchronization),它可以向企业 bean 警报事务的状态,包括由于服务器崩溃而失败的事务(假定不是拔了服务器的插头)。实现 SessionSynchronization 接口的企业 bean 必须定义三个已声明的方法特征符:afterBegin()、beforeCompletion() 和 afterCompletion(boolean)。这些方法使 bean 可以从容器接收三个额外的回调,以允许正确处理 bean 中的事务状态。
EJB 组件性能
从性能的角度看,servlet 和无状态会话 bean 是相当具有竞争力的技术。它们都可以使用实例池为来自客户机的请求提供服务。但是,当您添加了应用程序状态管理时,巨大的性能差异就将显现。与可用作 Servlet 体系结构一部分的轻量级 HTTPSession 机制不同,有状态会话 bean 需要一个更加重量级的针对状态管理(如上面概述的钝化/激活方案)的解决方案。这个针对有状态会话 bean 的常用解决方案需要花费服务器时间和资源来钝化 bean 状态、回收 bean 实例和激活 bean 状态。上述的每个过程都需要几次容器调用,以及需要直接对 bean 执行回调方法,以确保正确处理 bean 的状态。总而言之,有状态会话 EJB 组件为管理应用程序状态提供了一种重量级机制。