6.4.4 EJB的生命期
不同企业Bean具有不同的生命期。如前所述,会话Bean表示客户端,而实体Bean表示持久数据。会话Bean实例在客户端启动会话时创建;当客户端完成活动时,将销毁会话Bean实例。同样,在创建数据时,将创建实体Bean实例;而当销毁数据时,将销毁实体Bean的实例。
下面几节将描述不同企业Bean的生命期。
1. 无状态会话Bean的生命期
创建无状态会话Bean。在收到客户端请求时,业务层容器将调用以下方法创建无状态会话Bean:
● newInstance()
● setSessionContext(...)
● ejbCreate()
这些方法按以上顺序调用。newInstance()和ejbCreate()方法不接收任何参数。图6-19显示了无状态会话Bean的完整生命期。

图6-19 无状态会话Bean的生命期。开始时,容器中没有EJB,或EJB未处于池化状态,如图中的
“不存在”状态所示。在收到创建无状态会话EJB的请求时,容器将触发,并按向下箭头的
方向调用3个方法。如果这3个方法成功执行,将创建Bean,使Bean进入“就绪”状态。客
户端可调用处于就绪状态的Bean,以调用业务方法。当容器决定销毁Bean实例时,将调用
ejbRemove()方法,并销毁EJB,或将EJB放回Bean池
在调用newInstance()时,将创建一个会话Bean实例,但这个实例没有处于就绪状态。setSessionContext(...)方法接收一个称为SessionContext对象的参数。SessionContext对象包含Bean需要的所有上下文信息。在最后一个创建步骤,容器将调用ejbCreate()方法。如果成功调用了这个方法,就标志着Bean实例创建完成,可以接收客户请求。
无状态会话Bean的活动和服务。客户端可调用Bean的业务方法。业务方法可根据业务要求的性质执行任何工作,如持久数据活动。在方法完成活动后,将生成并返回响应,这标志着会话的结束。
销毁无状态会话Bean。容器将调用Bean的ejbRemove()方法。
在执行完业务方法和完成会话后,将调用这个方法。如果方法调用成功,将销毁这个Bean,并将所有资源释放到容器。
2. 有状态会话Bean的生命期
有状态会话Bean的生命期与无状态会话Bean有一些不同。
有状态会话Bean的创建。在接收到用户请求时,业务层容器调用以下方法创建有状态会话Bean。
● newInstance()
● setSessionContext(...)
● ejbCreate(...)
这些方法的调用按以上顺序进行。与无状态会话Bean不同,只有newInstance()方法不接收任何参数。图6-20显示了有状态会话Bean的完整生命期。

图6-20 有状态会话Bean的生命期。开始时,容器中没有EJB(或EJB未处于池化状态),即处于“不
存在”状态。在接收到创建有状态会话Bean的请求后,将按向下箭头所示的方向调用3个方
法。在这些方法成功执行后,将创建有状态会话Bean。这些Bean处于“就绪状态”,能处理
来自客户端的业务请求。由于这些EJB有状态,故需做“钝化”处理;容器可通过调用流程
涉及的“就绪”状态Bean上的ejbPassivate()方法,触发钝化保护。如从“就绪”状态发出的
另一向下箭头所示。钝化EJB不受永久支持,在超出时限后,将销毁Bean,或将EJB返回到
Bean池
在调用newInstance()方法后,将创建会话Bean实例,这个实例未处于就绪状态。SetSessionContext(...)方法将SessionContext对象作为参数。SessionContext对象包含Bean需要的所有上下文信息。在最后一个创建步骤中,容器调用ejbCreate(...)方法。这个方法的成功调用标志着Bean实例创建完成。此时的Bean可以接收客户请求。
有状态会话Bean的活动和服务。客户端可以调用这个Bean上的一个或多个业务方法,业务方法可根据业务要求的性质执行任何工作,如持久数据活动。在方法完成活动后,将生成并返回响应,这标志着会话的结束。
与无状态会话Bean略有不同,有状态会话Bean的服务和活动要求:Bean要在多个方法调用过程中维护会话状态。
为了在多个方法调用的过程中维护会话状态,有状态会话Bean占用的资源比无状态会话Bean多,需要长时间维护钝化状态,以满足资源或用户的要求。为此,容器使用另两个方法来管理和维护会话状态,如下:
● ejbActivate()
● ejbPassivate()
这两个方法不接收任何参数。
为等候的Bean调用ejbPassivate()时,将释放所有资源和Bean,使Bean进入钝化状态。
释放后的资源可供其他Bean使用。不过,如果客户端长期不活动,则容器不能无限期地保留资源。容器可能根据自身设置,永久销毁Bean,将资源提供给其他Bean使用。
而当钝化Bean准备执行操作时,容器将调用Bean的ejbActivate()方法,以便从辅助存储中恢复Bean的状态。
有状态会话Bean的销毁。容器将调用Bean上的ejbRemove()方法。
在完成了与特殊会话对应的所有业务方法后,就会调用这个方法。在成功执行这个方法后,将销毁Bean,并将所有资源释放给容器。
3. 实体Bean的生命期
实体Bean的生命期比会话Bean的复杂,但二者也有一些共同点。图6-21和图6-22显示了实体Bean的整个生命期。

图6-21 实体Bean的生命期(池化状态)。这里显示了实体Bean的完整生命期,并突出显示池化部分。
“池化”是一个中间状态。这个状态的实体Bean不与任何特定数据对应。可在这个状态的实
例上执行ejbHome()或ejbFind()等通用操作。当这些Bean无用时,容器将调用unsetEntity Contest()
方法销毁池化Bean

图6-22 实体Bean的生命期(就绪状态)。连续调用ejbCreate()和ejbPostCreate()方法使Bean进入“就
绪”状态。激活方法也能使Bean进入就绪状态。在执行业务方法时,同步方法ejbLoad()和
ejbStore()在“就绪”状态的实体Bean上适当运行
创建实体Bean。容器调用以下方法创建实体Bean实例:
newInstance()
setEntityContext(...)
与会话Bean一样,容器调用newInstance()创建Bean实例,但这个实例未处于就绪状态。
调用setEntityContext(...)使新建Bean能识别运行时上下文信息,该方法将Entity Context属性对象作为参数。
实体Bean的活动和服务。池化的Bean不表示任何特定数据。对于这样的实体Bean实例而言,不能调用其业务方法。可利用池化Bean执行一些通用活动,另外,当容器不再需要池时,可进行销毁。在这个阶段,可以执行如下3个动作:
● 调用ejbHome(),在Bean实例上执行一些通用操作
● 调用ejbFind(),以查找持久数据集合
● 调用unsetEntityContext()方法销毁Bean实例,并对实例进行无用单元回收处理
图6-22显示了就绪状态的实体Bean。如果需要新建数据,容器将从Bean池选一个实例,并按顺序调用以下方法:
● ejbCreate()
● ejbPostCreate()
在企业Bean中,ejbCreate()方法将接收大量参数,符合主键概念。因此,可能使用大量重载的ejbCreate()方法,以满足企业持久数据定义的需要。在供应业务数据时,ejbCreate()方法用供应值刷新Bean实例的实例变量。
现在,可以在这个Bean上运行ejbPostCreate()方法,以完成Bean的创建。这时,Bean就进入“就绪”状态,可以接受业务方法调用。
在实体Bean实例就绪后,它实际上将与数据库表的特殊记录等例子对应。现在,可在特定Bean实例上运行业务方法。在这样的Bean上运行业务方法是一项复杂活动,因为多个客户端可能同时访问此类持久数据。为此,容器需要将Bean上的方法调用与数据库保持同步。容器必须确保客户端总能访问到最新的持久数据。这可通过以下两种数据同步方法实现:
● ejbStore()
● ejbLoad()
在Bean实例上的业务方法将触发以下一系列事件:
● 调用ejbLoad()方法,并用来自数据库的最新值更新Bean的属性
● 业务方法在具体的Bean实例上运行。业务方法调用可能导致Bean实例变量值的变化,并改变Bean的状态
● 调用ejbStore()方法。该方法将Bean实例的最新值保存在数据库表的记录中
如图6-22所示,与有状态会话Bean一样,实体Bean可能要在长时间内处于不活动状态。如果出现这种情况,容器可能决定将Bean换出,并将资源分配给活动Bean。相反地,容器也可能决定将Bean换入,将其激活,将处于钝化状态的实体Bean转换为就绪状态。下面来描述这两个阶段。
钝化。当容器决定换出Bean时,将按顺序调用以下方法:
● ejbStore()
● ejbPassivate()
这将使Bean进入池化状态,并将Bean的数据存在辅助存储器中。
激活。当容器决定换入Bean时,将按顺序调用以下方法:
● ejbActivate()
● ejbLoad()
销毁实体Bean。如果特定实体Bean不再需要,容器将调用Bean上的ejbRemove()方法。这个操作使特殊Bean实例从“就绪”状态进入“池化”状态。容器可能在未来某个时间用池中实例表示另一条记录。
4. 消息驱动Bean的生命周期
在所有Bean中,“消息驱动Bean(MDB)”的生命期最简单。消息驱动Bean属于轻量级类型,不能直接被任何本地或外部客户端访问。
MDB的创建。容器调用3个方法创建MDB实例:
● newInstance()
● setMessageDrivenContext()
● ejbCreate()
与无状态会话Bean一样,newInstance()方法调用将创建一个Bean,这个Bean未处于就绪状态。接下来,容器调用这个实例上的setMessageDrivenContext()方法,以便使实例识别上下文信息。此后将调用ejbCreate()方法,使MDB实例进入“池化”状态。
MDB的活动和服务。当业务方法onMessage()接收到JMS消息时,池化MDB将转入操作状态。消息必须是JMS支持的类型,接下来,将启动一个适当的JMS操作。
MDB的onMessage()可能接收以下类型的消息对象:
● TextMessage
● ByteMessage
● ObjectMessage
● StreamMessage
● MapMessage
开发人员需要正确识别消息类型,理解内容,并进行适当操作。操作将成为进行中的业务流程的一部分。
发送电子邮件消息、更新数据库是一些JMS操作实例。
销毁MDB。当容器不再需要MDB实例时,将调用Bean上的ejbRemove()方法,以释放Bean占用的所有资源。
6.4.5 EJB的高级特性
当前的EJB 2.1和较早的EJB 2.0在很多方面进行了创新。除了引入更新类型的Bean—— MDB外,还提供了很多新功能,使企业Bean更强大、更可靠。
在众多的新特性中,CMP Bean中的高级特性最值得一提,下面列出了这个新规范的一些重大创新:
● Home方法(又称Home业务方法)
● 抽象持久模式(Abstract Persistence Schema),与之前的直接持久模式相对。这个新规范引入了“持久管理者”概念。持久管理者在运行时自动处理CMP实体Bean的持久性;基于新持久管理者合约“抽象持久模式”,将实体Bean映射到数据库;基于新查询语言EJB QL实施和执行finder方法
● 一种新型的专门查询语言“EJB查询语言”有助于简化finder方法,并使其独立于数据库
● 使用CMP Bean管理关系
● 本地接口,方便了与处在同一位置的Bean的通信,提高了容器内实体关系的效率
后续章节将介绍其中一部分特性。






