UML软件工程组织


创建有状态会话类型EJB组件
作者:苏洋 本文选自:赛迪网 2002年12月09日

我们根据是否维护客户端应用在EJB服务器中的状态,可以将会话类型EJB组件分为有状态(Stateful)和无状态(Stateless)两种类型。无状态类会话组件中不能够保持客户端应用状态,EJB容器可以利用同一无状态类型会话组件来处理不同的客户端请求,即使该EJB组件处于一个事务中。而在有状态类会话组件中,EJB组件实例与创建EJB组件的客户端应用之间存在着一一对应的关系,EJB容器代理客户端应用对有状态会话类型EJB组件实例中方法的调用。

在本讲中,我们将创建一个用于计算纳税额并存储纳税人姓名的有状态会话类型EJB组件TaxRecordEJB。

EJB系列讲座

第一讲:分布式多层体系结构

第二讲:EJB基本结构解析

第三讲:EJB会话组件分析

第四讲:如何定义无状态会话类型EJB组件

定义EJB组件的Home接口

有状态会话类型EJB组件的Home接口用于定义EJB容器创建组件对象实例的create方法等。EJB组件开发人员定义Home接口、由EJB容器来负责实现该接口中的方法。TaxRecordEJB组件的Home接口定义如下:

// TaxRecordHome.java
import javax.ejb.*;
import java.rmi.*;
public interface TaxRecordHome extends EJBHome
{
TaxRecord create() throws
CreateException,RemoteException;
TaxRecord create( float fRate ) throws
CreateException,RemoteException;
}

与无状态会话类型EJB组件相比,在有状态会话类型EJB组件的Home接口中可以定义任意数量异构类型的create方法,而不是像在无状态会话类型EJB组件的Home接口中那样只能定义一个没有参数的create方法。

定义EJB组件的Remote接口

EJB组件的Remote接口用于定义客户端能够调用的组件商务方法。该接口由组件开发人员编写、由EJB容器负责实现。TaxRecordEJB组件对象的Remote接口定义代码如下:

//TaxRecord.java
import javax.ejb.*;
import java.rmi.RemoteException;
public interface TaxRecord extends EJBObject
{
float calcTax ( float fAmount, String name )
throws RemoteException,UserException;
}

在上述Remote接口定义中,包含客户端能够调用的组件商务方法calcTax。该方法根据由参数传递的收入数额计算应纳税额并返回浮点数类型的计算结果。在Remote接口中定义的商务方法除了必须抛出RemoteException异常外,还可以抛出用户定义类型异常。在第四讲中已经对用户异常的定义方式进行过讲解,在此不再赘述。

定义EJB组件类

EJB组件类用于实现在Home接口中定义的create方法、Remote接口中定义的商务方法以及SessionBean接口中定义的组件生命期方法。

实现Home接口中定义的create方法

在TaxRecordEJB组件对象的Home接口中定义了两个异构形式的create方法。EJB规范定义在组件的Home接口中定义的create方法映射到组件类中的方法为参数和返回值类型相同、名称为ejbCreate方法。映射到组件类中的两个创建组件对象实例方法的实现代码如下:

public void ejbCreate()
{
this.fRate = 0.10f;
nameList = new Vector();
}
public void ejbCreate( float fRate )
{
this.fRate = fRate;
nameList = new Vector();
}

在EJB组件类中定义了用于定义税率的成员变量fRate以及存储纳税人姓名的向量类型成员变量nameList。在ejbCreate方法中除了对fRate赋初始值外,还创建向量类型对象实例nameList。

在组件类中定义的ejbCreate方法与组件的Home接口中定义的create方法的区别在于组件类中的ejbCreate方法的返回值为缺省(void),而组件的Home接口中定义的create方法的返回值类型为组件的Remote接口,请读者注意这方面的区别。

实现Remote接口中定义的商务方法

在TaxRecordEJB组件对象的Remote接口中定义了计算纳税额的商务方法calcTax,客户端在创建组件对象实例后可以调用该方法获取服务。该方法的实现代码如下:

float calcTax( float fAmount, String name )
{
if( fAmount<0 || name.length == 0 )
throw new RemoteException("Invalid parameter");
else if( fAmount<800 )
{
nameList.addElement(name);
return 0;
}
else
{
nameList.addElement(name);
return (fAmount-800)*fRate;
}
}

在calcTax方法的实现代码中,首先判断收入数额fAmount是否大于零并且纳税人姓名是否为空。然后,根据当前税率值fRate和方法参数传递的收入数额计算应纳税额并将纳税人的姓名保存在向量类实例nameList中。

实现SessionBean接口中定义的方法

在第四讲中曾经介绍过SessionBean接口中各个方法的作用。在编写有状态会话类型EJB组件的组件类代码时,只需在setSessionContext方法中将EJB容器的上下文信息记录在组件类的会话上下文(SessionContext)成员变量中,用于EJB容器再次调用该组件实例的商务方法时获取组件的运行环境信息,不需要为其它方法编写实现代码。EJB组件类中实现的SessionBean接口的方法代码如下:

public void ejbRemove(){}
public void ejbActivate(){}
public void ejbPassivate(){}
public void setSessionContext(SessionContext ctx){this.ctx = ctx;}

EJB组件类的定义框架

TaxRecordEJB组件类定义的框架代码如下:

//TaxRecordBean.java
public class TaxRecordBean implements SessionBean
{
private float fRate;
private Vector nameList;
private SessionContext ctx;
//构造方法
public TaxRecordBean(){}
//3.1节中实现Home接口中定义的create方法
… …
//3.2节中实现Remote接口中定义的商务方法
… …
//3.3节中实现SessionBean接口中定义的方法
… …
}

在EJB组件类中定义了浮点数类型的成员变量fRate、向量类型成员变量nameList、会话上下文对象实例ctx以及3.1-3.3节中定义的各个方法的实现代码。除此之外,EJB规范规定在EJB组件类中必须定义一个没有参数的公共(public)类型构造函数。

会话类型EJB组件的客户端调用方式

基于J2EE规范的客户端应用通常是指用于创建EJB组件对象实例、调用组件商务方法的部署在WEB服务器中的WEB组件。这种类型的WEB组件由多个JSP文件或者Servlet文件构成,其中包括创建和删除组件对象实例以及调用组件商务方法的代码。下面将分别对客户端创建无状态和有状态会话类型EJB组件以及客户端调用组件商务方法的方式进行说明:

创建无状态会话类型EJB组件对象实例

根据对整个应用系统的运行过程进行分析,客户端应在创建第四讲中编写的用于获取税率的无状态会话类型EJB组件TaxRateEJB对象的实例后,调用该组件实例的getTaxRate方法获取计算纳税额的税率。创建无状态会话类型EJB组件对象实例以及调用组件商务方法的代码如下:

InitialContext ctx = new InitialContext();
Object obj = ctx.lookup("java:comp/env/TaxRate/TaxRateEJB");
TaxRateHome taxRateHome = (TaxRateHome)PortableRemoteObject.narrow(
obj,TaxRateHome.class);
TaxRate taxRate = (TaxRate)taxRateHome.create();
float fCurrentRate = taxRate.getTaxRate();

上述代码利用JNDI方法定位TaxRateEJB组件对象实例的Home接口后,调用组件Home接口中定义的create方法在EJB容器中创建无状态会话类型EJB组件对象实例并调用组件的getTaxRate方法获取税率。

创建有状态会话类型EJB组件对象实例

创建有状态会话类型EJB组件对象实例的代码如下:

InitialContext ctx1 = new InitialContext();
Object obj = ctx1.lookup("java:comp/env/TaxRecord/TaxRecordEJB");
TaxRecordHome taxRecordHome = (TaxRecordHome)PortableRemoteObject.narrow(
obj, TaxRecordHome.class);
TaxRecord taxRecord = taxRecordHome.create( fCurrentRate );

上述代码在定位组件对象的Home接口后调用在Home接口中定义的create方法创建组件对象实例。需要注意的是:在create方法的调用参数中,fCurrentRate为4.1节中调用无状态会话类型EJB组件对象实例的getTaxRate方法获取的计算纳税额税率。

比较无状态会话类型EJB组件对象实例以及调用组件商务方法的代码和有状态会话类型EJB组件对象实例的代码可以看出:在创建有状态和无状态会话类型EJB组件对象实例代码中,除了获取对Remote接口对象引用的代码有所区别外,其它代码的形式均类似。

调用组件商务方法

调用EJB组件中定义的商务方法与JDK程序设计中调用类的成员方法类似,见下面的代码:

float fTaxAmount = taxRecord.calcTax( 1000.0f, "Johnson");

上面的代码调用calcTax方法计算当收入为1000.0时的应纳税额,此时应用的税率为创建TaxRecordEJB组件对象实例时传递的参数fCurrentRate。

(责任编辑 Sunny)



版权所有:UML软件工程组织