会话组件(Session Beans)

<script type="text/javascript"> google_ad_client = "pub-8800625213955058"; /* 336x280, 创建于 07-11-21 */ google_ad_slot = "0989131976"; google_ad_width = 336; google_ad_height = 280; // </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> 胡德平 编译(hudeping@263.net www.JavaUnion.org) 会话组件在J2EE服务器中表现为一个客户端,该客户端通过调用会话组件方法获取远程服务。会话组件为其客户端完成指定任务,屏蔽了客户端需要在服务器端执行商业任务的复杂性。 正如其名所暗示,会话组件工作原理类似于交互会话。会话组件是不共享得--它在会话期间只能与一个客户端交互、一个用户交互。和交互会话一样,会话组件没有持续,当客户端中断会话后会话组将也将中断并不再与客户端相关联。 会话组件是非常有用而强大的,因为它将你的客户端范围扩展到了远程服务器--并且它们容易开发。本文将通过简单示例,为你展示如何编写、编译和部署一个简单的会话组件。 会话组件示例 本文所举例子是一个在线书店中关于购物车的演示,组件的客户端需要实现往购物车增加、删除、查询等操作功能。为了实现这个例子,你需要完成下面程序的编码: ·会话组件类(CartEJB.java) ·本地接口(CartHome.java) ·远程接口(Cart.java) 上述三个文件在所有企业组件(EJB)编程中都是必须的,为了满足特定应用更多需求,企业组件可能需要更多的帮助类(helper class)。CartEJB会话组件使用了两个帮助类,即 BookException.java和IdVerifier.java。 如果你安装了J2EE,上述源码文件可以在doc/guides/ejb/examples/cart目录中找到。 会话组件类 本例子中会话组件类命名为CartEJB.,与其它所有的会话组件一样, CartEJB 类必须满足以下要求: ·实现SessionBean 接口 ·类定义为公共类(public) ·类不能是抽象类或终极类 ·实现一个或多个ejbCreate方法 ·实现商业方法 ·有无参数的构造方法 ·必须没有终极方法(finalize method) CartEJB源码如下:


import java.util.*; 

import javax.ejb.*; 



public class CartEJB implements SessionBean { 



String customerName; 

String customerId; 

Vector contents; 



public void ejbCreate(String person) throws CreateException { 



if (person == null) { 

throw new CreateException("Null person not allowed."); 

} 

else { 

customerName = person; 

} 



customerId = "0"; 

contents = new Vector(); 

} 



public void ejbCreate(String person, String id) 

throws CreateException { 



if (person == null) { 

throw new CreateException("Null person not allowed."); 

} 

else { 

customerName = person; 

} 



IdVerifier idChecker = new IdVerifier(); 

if (idChecker.validate(id)) { 

customerId = id; 

} 

else { 

throw new CreateException("Invalid id: "   id); 

} 



contents = new Vector(); 

} 



public void addBook(String title) { 



contents.addElement(title); 

} 



public void removeBook(String title) throws BookException { 



boolean result = contents.removeElement(title); 

if (result == false) { 

throw new BookException(title   " not in cart."); 

} 

} 



public Vector getContents() { 

return contents; 

} 



public CartEJB() {} 

public void ejbRemove() {} 

public void ejbActivate() {} 

public void ejbPassivate() {} 

public void setSessionContext(SessionContext sc) {} 



} 

会话组件接口(SessionBean) 会话组件接口SessionBean继承EnterpriseBean 接口,而后者继承了Serializable 接口。SessionBean 接口定义了ejbRemove, ejbActivate, ejbPassivate 和setSessionContext 方法。CartEJB 类没有用到这些类,但必须实现它们否则应该定义成抽象类。因此,这些方法在CartEJB类中被声明为空方法,随后的内容中将就这些方法何时有什么用途进行说明。 EjbCreate方法 由于企业组件运行在EJB容器中,所以客户端无法直接示例化这些组件。只有EJB容器可以示例化企业组件,在本文所述例子中完成实例化需要实现以下步骤: 1. 客户端调用本地接口的create方法: Cart shoppingCart = home.create("Duke DeEarl","123"); 2. EJB容器实例化企业组件。 3. EJB容器调用CartEJB中对应的ejbCreate方法:


public void ejbCreate(String person, String id) 

throws CreateException { 



if (person == null) { 

throw new CreateException("Null person not allowed."); 

} 

else { 

customerName = person; 

} 



IdVerifier idChecker = new IdVerifier(); 

if (idChecker.validate(id)) { 

customerId = id; 

} 

else { 

throw new CreateException("Invalid id: "   id); 

} 



contents = new Vector(); 

} 

典型的, ejbCreate 创建方法初始化企业组件的状态。前面所提到的ejbCreate方法,如通过create方法传递参数初始化客户名( customerName )和客户ID( customerId )变量。 企业组件可以有一个或多个ejbCreate 方法,方法的命名必须满足下面需求: ·访问控制修饰词必须是public. ·返回值必须是void. ·参数必须是Java RMI的合法类型 ·修饰词(modifier)不能是static或final. 此外,异常抛出必须包括javax.ejb.CreateException 和其它你应用中指定需要抛出的异常。如果输入的参数无效,ejbCreate 方法通常抛出CreateException 异常。 商业方法 会话组件的最根本的用法是实现客户端所需要的商业任务,客户端通过create方法返回的参考调用远程对象的商业方法。从客户端角度看,商业方法是在本地运行的,但实际上是在远程会话组件中运行,下面的代码摘录描述了CartClient程序中对商业方法的调用过程:


Cart shoppingCart = home.create("Duke DeEarl", "123"); 

. . . 

shoppingCart.addBook("The Martian Chronicles"); 

shoppingCart.removeBook("Alice In Wonderland"); 

bookList = shoppingCart.getContents(); 

The CartEJB class implements the business methods in the following code: 

public void addBook(String title) { 



contents.addElement(new String(title)); 

} 



public void removeBook(String title) throws BookException { 



boolean result = contents.removeElement(title); 

if (result == false) { 

throw new BookException(title   " not in cart."); 

} 

} 



public Vector getContents() { 

return contents; 

} 



商业逻辑的用法必须符合下面的规则: ·方法名不能与EJB体系结构规范中定义的有冲突,如不能命名为ejbCreate、ejbActive等 ·访问控制修饰符必须是public ·参数类型必须是合法的Java RMI类型 ·修饰词不能为static或final 方法抛出异常语句可能包括为具体应用而定义的异常,如当书不在购物车中时removeBook方法抛出BookException 异常。 为了指出如无法连接数据库这样的系统级错误,商业方法需要抛出javax.ejb.EJBException 异常。当商业方法抛出EJBException时,EJB容器将其包装成客户端捕获得RemoteException 异常。对于应用定义的异常BookException,容器是不会对其进行包装的,因为EJBException 是RuntimeException 异常的子类。 本地接口 本地接口继承EJBHome接口,主要用于定义客户端调度的create方法,如CartClient调用create方法: Cart shoppingCart = home.create("Duke DeEarl", "123"); 在本地接口中每个create 方法与组件类的一个ejbCreate 方法相对应,在CartEJB类中的ejbCreate方法的用法如下:
 

public void ejbCreate(String person) throws CreateException 

. . . 

public void ejbCreate(String person, String id) 

throws CreateException 

比较一下ejbCreate 与CartHome中create 方法的用法:


import java.io.Serializable; 

import java.rmi.RemoteException; 

import javax.ejb.CreateException; 

import javax.ejb.EJBHome; 



public interface CartHome extends EJBHome { 

Cart create(String person) throws RemoteException, 

CreateException; 

Cart create(String person, String id) throws RemoteException, 

CreateException; 

} 

ejbCreate与 create 方法的用法类似,当在重要的方面是不一致的,本地接口中create方法的使用原则定义如下: ·create方法的参数数量和类型必须与所定义的ejbCreate 方法一致 ·create方法参数和返回类型必须是合法的RMI类型 ·create 方法企业组件远程接口类型(而djbCreate方法返回空) ·create方法异常抛出语句必须包括java.rmi.RemoteException和javax.ejb.CreateException 远程接口 远程接口继承于javax.ejb.EJBObject, 定义了客户端可以调用的商业方法,下面是购物车的远程接口代码 :


import java.util.*; 

import javax.ejb.EJBObject; 

import java.rmi.RemoteException; 



public interface Cart extends EJBObject { 



public void addBook(String title) throws RemoteException; 

public void removeBook(String title) throws BookException, 

RemoteException; 

public Vector getContents() throws RemoteException; 

} 
远程接口定义方法必须遵循下述原则: ·每个在远程接口中定义的方法必须与企业组件类中多定义的方对应 ·远程接口中方法的用法必须与企业组件类中的方法一致 ·方法的参数和返回值必须是合法的RMI类型 ·异常抛出语句必须包括java.rmi.RemoteException 帮助类 CartEJB 组件有两个帮助类: BookException和 IdVerifier,其中 BookException 是应用定义的异常而IdVerifier 用于在djbCreate方法中验证customerId 的有效性。帮助类在J2EE应用打包时包含在EJB.jar文件中,与企业组件类在同一包。 状态管理模式 在为会话组件指定不属描述符时,不想选择会话组件的状态模式:有状态和无状态。 有状态会话组件(Stateful Session Beans) CartEJB 这个例子有三个实例变量:customerName, customerId, 和 contents,这些变量代表了购物车应用的会话状态。因为CartEJB 具有会话状态,所以把它叫做有状态会话组件。 状态在客户端与会话组件会话期间保留,当客户端移交(remove)组件、会话结束后状态消失。解决这种状态的短暂性不是什么问题,然而,因为客户端和组件之间会话结束后不再需要保留状态。 无状态会话组件(Stateless Session Beans) 无状态会话组件在会话期间不需要为特定的客户端保存状态,因而得名。当客户端调用无状态组件时,组件实例变量可能会有状态,但仅仅只是在调用过程中。当方法执行结束后,状态不再保留。除了方法调用期外,所有的无状态组件实例都是相等地,允许EJB容器将任何一个实例分配给任意一个苦户端。 因为无状态组件可以支持多个客户端,从拥有大量客户端的应用来客比有状态会话组件具有更大的灵活性。通常情况下,应用要求用更多的无状态组件而非有状态组件来相应相同的客户端。 有时,EJB容器会将状态组件写到缓存中,但无状态组件是从来不会这么做的。因此,相对而言无状态组件能够提供比有状态组件更高的性能。 无状态组件的本地接口必须有一个无参数的create 方法,同时会话组件也必须有个与其相对应的无参数ejbCreate 方法。 两种会话组件的选择 下列情况下,建议选择有状态组件: ·在组件创建时必须初始化其状态 ·组件必须保留客户端方法商业方法的信息 ·客户端是交互式应用 既然会话组件的主要目的是在J2EE服务器上表现客户端功能,更多的会话组件会是有状态会话组件。不过,在下述情况下建议使用无状态会话组件: ·组件执行的任务不讲究是否对应特定客户端,如数据库查询 ·组件无需保留客户端对方法调用的信息 会话组件的生命周期 会话组件在其生命周期中有多个状态,其生命周期由EJB容器所管理而非应用本身。尽管应用无法管理组件的生命周期,但下面关于生命周期的信息对于管理如数据库连接的资源是有用的。 有状态会话组件的生命周期 有状态会话组件的生命周期源于客户端通过create 方法、EJB容器实例化组件后调用会话组件的setSessionContext 和ejbCreate 方法。此后,组件的商业方法处于可调用的就绪阶段。 在就绪阶段,EJB容器将判断组件是否可以处于非活动、钝化状态,然后将其从内存转移到缓存(典型的算法是采用最近最少调用算法),EJB容器调用组件的ejbPassivate 方法实现对组件的钝化。如果在钝化阶段有客户端调用该组件的商业方法,EJB容器将激活组件并将其恢复到就绪状态,然后调用组件的ejbActivate 方法。 在生命周期最后,客户端调用remove 方法、EJB容器调用组件的ejbRemove 方法,组件实例等待垃圾回收器回收处理。 在客户端编程中,主要通过调用两个生命周期相关方法-- create 和 remove 方法实现对生命周期的处理。下图中所有的方法调用都是由服务器端EJB容器实现的,如 ejbCreate 方法,允许你在组件实例化后进行数据库连接等操作。 图 有状态会话组件生命周期 五状态会话组件生命周期 因为无状态会话组件从来不被钝化,所有它的声明周期只有两个阶段:在商业方法调用过程中的不存阶段在和就绪阶段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值