===================================
提纲:
===================================
一、概述
二、无状态会话Bean
三、有状态会话Bean
四、客户端接口
4.1 Remote接口
4.2 Home接口
五、实例
5.1 有状态会话Bean
5.2 Home接口
5.3 Remote接口
5.4 部署描述器
5.5 客户程序
5.6 运行
===================================
正文:
===================================
一、概述
在企业级应用系统内,会话Bean是一种代表客户程序执行操作的EJB。对于EJB客户程序来说,会话Bean常常起着入口点或“前线”EJB的作用。EJB客户程序通过与会话Bean的交互,从企业应用系统获取它们想要利用的功能或服务。
正如其名字所示,会话Bean类似于一个交互式的会话。会话Bean是不共享的,正如交互式会话只能有一个用户,而且会话Bean也不具备持久化的特点(即它的数据不保存到数据库)。一旦客户程序结束运行,会话Bean也就不再关联到客户程序。
会话Bean有两种类型:有状态会话Bean(Stateful Session Bean),无状态会话Bean(Stateless Session Bean)。
有状态会话Bean
对象的状态由实例变量的值描述。对于有状态会话Bean,实例变量描述了客户程序与Bean的会话的状态。鉴于客户程序与Bean的交互关系,Bean的状态信息通常称为会话状态。
在客户程序与Bean交互期间,状态信息一直有效。如果客户程序运行结束或拆除了Bean,则会话结束,状态信息也不再保留。然而,状态信息的这种临时性并不成为问题,因为当客户程序与Bean之间的会话终止,状态信息也就没有必要再保存了。
无状态会话Bean
无状态会话Bean不为特定的客户程序保留会话状态。客户程序调用无状态Bean的方法时,Bean的实例变量可以包含状态信息,但状态信息仅在该次调用期间有效。当方法调用结束,状态信息也就不再保留。除了Bean方法正在执行的时间之外,所有无状态Bean的实例都是等价的,这使得EJB容器能够把Bean的实例分配给任意客户程序。
由于无状态会话Bean支持多个客户程序,对于那些客户程序数量很大的应用,无状态会话Bean具有更好的可伸缩性。一般地,对于支持同样数量的客户程序来说,应用需要的无状态会话Bean数量少于有状态会话Bean数量。
一些时候,EJB容器可能把有状态会话Bean保存到第二级存储设备,但容器永远不会保存无状态会话Bean。因此,无状态会话Bean比有状态会话Bean有着更好的性能。
一般地,在下列情形下,我们可以使用会话Bean:
在任意时刻只有一个客户程序访问Bean的实例。
Bean的状态无需持久化,只在短期内生存(比如几个小时)。
如果满足任意以下条件,使用有状态会话Bean比较合适:
Bean的状态描述了Bean与特定客户程序的交互。
Bean需要保留有关客户程序的信息,且保留期限必须跨越多次方法调用。
Bean担负着客户程序到应用其他组件之间的中间人的角色,为客户程序提供一个简化的服务视图。
Bean管理着多个EJB的工作流程。
为提高性能,当Bean具有任意下面的特征之一时,最好选用无状态会话Bean:
Bean的状态信息不包含任何针对特定客户程序的数据。
Bean从数据库提取一组客户程序经常使用的只读数据。例如,Bean从数据库提取出本月销售的产品信息。
二、无状态会话Bean
无状态会话Bean不在EJB之内保留面向特定客户程序的状态信息,但这并不意味着这类EJB不在本身的域或关联的对象里面保留任何状态数据,其真实含义是,这类Bean保持的状态信息不是为特定EJB客户程序下一次访问或使用而保留。
这种特点使得EJB容器能够更高效、更灵活地管理无状态会话Bean。在任意时刻,任意一个客户程序可以使用容器创建的任意一个无状态会话Bean的实例。因此,容器可以为这类实例构造一个缓冲池,根据客户程序的需求从缓冲池分配Bean的实例,无需顾虑哪一个实例属于哪一个客户程序。此外,必要时容器能够方便地创建或拆除Bean的实例,根据应用规模和资源情况作出调整。虽然无状态会话Bean可能拥有状态信息,但在两次对Bean实例的连续调用之间,开发者不能假定这些状态信息的合法性。
图一显示了无状态会话Bean组件构造的基本体系结构。
[[The No.1 Picture.]]
位于图一顶端的是javax.ejb.EnterpriseBean接口,它是所有EJB的基础接口。从EnterpriseBean接口派生出了javax.ejb.SessionBean接口。公用的、非最终的、非抽象的无状态会话EJB,比如图一显示的MyStatelessSessionEJBean,必须实现javax.ejb.SessionBean接口。无状态会话EJB实现公用的、非最终的、非抽象的业务方法,比如图一显示的someMethod()和anotherMethod()。实现会话Bean的类必须有一个公用的、不带参数的构造函数,且不应该实现finalize()方法。
无状态会话Bean上定义的setSessionContext()方法用来把一个SessionContext的实例传入EJB,它也是SessionBean接口上定义的第一个由容器调用的方法。SessionContext对象封装了一个EJB会话容器上下文的接口,支持会话Bean的实例访问容器提供的运行时会话上下文。在Bean实例生存期间,会话上下文将一直保持与Bean实例的关联。
对于无状态会话Bean,尽管在SessionBean接口中没有定义ejbCreate()方法,但它是一个关键的操作。无状态会话Bean必须定义一个返回值为void的ejbCreate()方法,容器准备创建Bean的实例时将调用这个方法。容器决定创建Bean的实例可能是因为它要构造一个Bean实例的缓冲池,也有可能是因为它接收到了客户程序的请求。因此,ejbCreate()方法属于一种由EJB实现的特殊的构造函数或初始化方法。
当容器决定不让Bean的实例继续处理客户程序的请求时,它就会调用Bean实例的ejbRemove()方法。对于无状态会话Bean,何时调用Bean实例的ejbRemove()方法由容器单独决定,不受EJB客户程序的任何影响。
三、有状态会话Bean
有状态会话Bean在EJB之内保留的状态信息与EJB客户程序有着明确的关系。有状态会话Bean的状态信息是指保存在Bean实例的域里面的数据,以及Bean实例持有的各种对象里面的数据。当一个EJB客户程序在某一时刻访问一个有状态会话Bean,且改变了该Bean实例的状态,则状态信息将被保留,下一次Bean再次被访问时,Bean的实例将使用原先保存的状态信息。
对于有状态会话Bean,容器承担着更多的Bean管理方面的责任。实际上,客户程序创建或拆除有状态会话Bean直接关系到服务器端Bean实例的创建和拆除。此外,当资源紧张时,容器可能决定把一个或者多个有状态会话Bean串行化(也就是钝化)到持久性存储设备,一旦资源重新空闲,或出现了客户程序的请求,被钝化的Bean必须激活并转入活动内存。因此,设计有状态会话Bean时,开发者必须考虑更多的问题。
图二显示了有状态会话Bean组件构造的基本体系结构。
[[The No.2 Picture.]]
公用的、非最终的、非抽象的有状态会话Bean,如图二显示的MyStatefulSessionEJBean,必须实现SessionBean接口。SessionBean接口从EnterpriseBean接口派生。另外,有状态会话EJB也实现公用的、非最终的、非抽象的业务方法,比如图二显示的someMethod()方法和anotherMethod()方法。实现会话Bean的类必须有一个公用的、不带参数的构造方法,且不应实现finalize()方法。最后,有状态会话Bean可以实现javax.ejb.SessionSynchronization接口,使得Bean能够收到某些事务管理方面的事件通知,但这是可选的。
由于状态信息对于有状态会话Bean的重要性,创建Bean时初始化操作也很重要。有状态会话Bean可以定义一个或者多个ejbCreate(...)方法,这些方法带有零个或者多个输入参数,方法的返回值类型是void。传递给这类方法的具体参数由应用本身决定,但方法的名字必须是ejbCreate()。与无状态会话Bean上的ejbCreate()调用不同,有状态会话Bean的ejbCreate()方法绑定到EJB客户程序,EJB客户程序将一直使用特定的EJB实例。另外也请注意,正如对于无状态会话Bean,在调用任何ejbCreate()方法之前,容器将调用有状态会话Bean的setSessionContext()方法。
如果有状态会话Bean的ejbRemove()方法被调用,则表明对应的客户程序已经决定不让该Bean继续处理请求。另外,会话最大超时时间到达时,容器也会调用Bean的ejbRemove()方法。
设计有状态会话Bean的过程中,有时最重要的事情就是Bean的钝化和激活操作。正如前面所指出的,容器钝化某个Bean时,它将串行化Bean的内容,并把这些信息写入某个持久性存储设备。容器之所以钝化Bean是因为内存资源不足。通常,容器通过某种形式的“最近最少使用”算法确定应该钝化哪些Bean的实例(当然,实际所用的算法由具体的平台决定)。
在钝化Bean的实例之前,容器会调用Bean的ejbPassivate()方法,有状态会话Bean必须实现这个方法。在ejbPassivate()方法中,我们应该清除所有不能串行化和持久化的资源,比如数据库连接和打开的文件句柄。ejbPassivate()方法执行完毕之后,所有仍未关闭的对象应该能够被容器钝化。
如果出现了对已经