2008年(3500)
分类:
2008-05-04 19:53:42
在以后的日子里,将由Jackliu向大家陆续提供一系列EJB教程,有学习EJB的朋友请同步参考EJB相关书籍,实战系列将以例程的方式帮助你理解这些基本的概念,其中将包括:
所有章节完毕后将制作成pdf电子文档,供大家下载。
实战EJB之二 开发会话Bean(无状态会话Bean)
会话Bean可以分为有状态会话Bean(stateful Bean)和无状态会话Bean(stateless Bean),有状态会话Bean可以在客户访问之间保存数据,而无状态会话Bean不会在客户访问之间保存数据。两者都实现了javax.ejb.SessionBean接口,EJB容器区通过部署文件ejb-jar.xml来判断是否为一个SessionBean提供保存状态的服务,另外,在程序实现上,无状态Bean不能声明实例变量,每个方法只能操作方法传来的参数。实际上,我们第一节中的第一个EJB程序就是一个无状态Session Bean。
在本节中你将了解到:
- 什么是无状态Session Bean?
- 无状态Session Bean寿命周期
- 编写一个无状态Session Bean程序
- 部署到应用服务器
- 开发和部署测试程序
- 运行测试程序
什么是无状态Session Bean?
无状态Session Bean每次调用只对客户提供业务逻辑,但不保存客户端的任何数据状态。但并不意味着stateless类型的Bean没有状态,而是这些状态被保持在客户端,容器不负责管理。如《再别康桥》中写到的"悄悄的我走了,正如我悄悄的来。挥一挥衣袖,不带走一片云彩"。
无状态Session Bean在EJB中是最简单的一种Bean,如果数据实际上是数据的瞬像,则建议使用无状态会话Bean。但是无状态会话Bean也有自己的问题,本该存储在服务器端(J2EE服务器)的数据被存储在客户中,每次调用这些数据都要以参数的方式传递给Bean,如果是一个比较复杂的数据集合,则网络需要传递大量数据,造成更多的负载。在客户端维护状态还要注意安全性问题,如果数据状态非常敏感,则不要使用无状态会话Bean,这些情况可以使用状态会话Bean,将用户状态保存到服务器中。
无状态Session Bean寿命周期
无状态Session Bean寿命周期由容器控制,Bean的客户并不实际拥有Bean的直接引用,当我们部署一个EJB时,容器会为这个Bean分配几个实例到组件池(component pooling)中,当客户请求一个Bean时,J2EE服务器将一个预先被实例化的Bean分配出去,在客户的一次会话里,可以只引用一次Bean,就可以执行这个Bean的多个方法。如果又有客户请求同样一个Bean,容器检查池中空闲的Bean(不在方法中或事务中,如果一个客户长时间引用一个Bean但执行一个方法后需要等待一段时间再执行另一个方法,则这段时间也是空闲的),如果全部的实例都已用完则会自动生成一个新的实例放到池中,并分配给请求者。当负载减少时,池会自动管理Bean实例的数量,将多余的实例从池中释放。 无状态Session Bean有两种状态:存在或不存在。
<图2-1>
当客户端不存在一个无状态Session Bean时,通过远程主接口的create()方法创建一个Bean,newInstance()负责将Bean实例化,EJB容器调用Bean类的setSessionContext()方法把运行环境对象SessionContext传递给Bean;随后调用Bean的ejbCreate方法进行必要的初始化和资源分配。在下面这个实战例子中,Bean的实现类就是StatelessDateEJB类。
编写一个无状态的Session Bean程序
这个Session Bean组件提供一个日期计算器,通过getDayInRange()方法计算两个日期之间相差的天数,通过getDayForOlympic()得到距离北京申办2008年奥林匹克运动会天数。并且我们为这个Bean起名为StatelessDate
设计一个无状态的Session Bean至少包括四个步骤:
- 开发主接口
- 开发组件接口
- 开发Bean实现类
- 编写部署文件
注意:本节假设你使用的Windows操作系统。如果使用其他操作系统,可能影响到存储路径和JDK命令,但这与程序代码和部署文件内容无关。
1.开发主接口(StatelessDateHome.java):
是由Bean开发人员编写的一个Bean的主接口(interface)程序,负责控制一个Bean的生命周期(生成、删除、查找Bean)。只需要开发人员给出一个主接口类,类方法的实现由容器来完成。 主接口扩展了javax.ejb.EJBHome接口,参考avax.ejb.EJBHome接口定义如下:
|
一般情况下,习惯将主接口的命名规则规定为
Home,所以我们把这个主接口类起名为StatelessDateHome 大部分逻辑方法已经被EJBHome定义,在我们要设计的远程主接口StatelessDateHome里,不必再重新定义。值得注意的是,我们需要为这个接口定义一个create()方法,用来获得一个实例Bean的引用,返回的对象类型是组件接口类StatelessDate。
StatelessDateHome.java代码:
import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; public interface StatelessDateHome extends EJBHome{ public StatelessDate create() throws RemoteException,CreateException; } |
假设我们保存到D:\ejb\StatelessDate\src\StatelessDateHome .java
2.开发组件接口(StatelessDate.java):
当远程用户调用主接口类生成方法(create())时,客户要得到一个组件的远程引用,因此EJB容器要求你为这个Bean的所有方法提供一个接口类,而类的实现则与远程主接口StatelessDateHome 一样由容器在部署时自动生成。
组件接口扩展了avax.ejb.EJBObject接口,参考avax.ejb.EJBObject接口定义如下:
|
一般情况下,习惯将组件接口的命名规则规定为
,所以我们把这个组件接口类起名为StatelessDate 大部分逻辑方法已经被EJBObject 定义,在我们要设计的组件接口StatelessDate里,不必再重新定义,只要我们重申组件中有关业务逻辑的接口即可。逻辑方法getDayInRange()得到两个日期间的天数间隔,如果输入的时间非法或不合适将抛出InsufficientDateException异常。逻辑方法getDayForOlympic()得到距离北京申办奥运会的天数,如果输入的时间非法或不合适将抛出InsufficientDateException异常。
StatelessDate.java代码:
import javax.ejb.EJBObject; import java.rmi.RemoteException; import java.util.Date; public interface StatelessDate extends EJBObject{ public int getDayInRange(Date lowerLimitDate,Date upperLimitDate) throws RemoteException,InsufficientDateException; public int getDayForOlympic() throws RemoteException,InsufficientDateException; } |
假设我们保存到D:\ejb\StatelessDate\src\StatelessDate .java
InsufficientDateException.java代码:
public class InsufficientDateException extends java.lang.Exception{ public InsufficientDateException(){} } |
假设我们保存到D:\ejb\StatelessDate\src\InsufficientDateException.java
3.开发Bean实现类(StatelessDateEJB.java):
这个类包含了业务逻辑的所有详细设计细节。会话Bean的实现类实现了(implements)javax.ejb.SessionBean所定义的接口,首先我们先熟悉一下SessionBean的定义:
package javax.ejb; impot java.rmi.RemoteException; public interface SessionBean extends EnterpriseBean{ public void setSessionContext(SessionContext ctx) throws EJBException,RemoteException; public void ejbRemove() throws EJBException,RemoteException; public void ejbActivae()throws EJBException,RemoteException; public void ejbPassivate()throws EJBException,RemoteException; } |
容器通过这些方法将相关信息通知给Bean实例,所有的方法都抛出RemoveException方法是为了与1.0规范兼容,之后版本编写的Bean只需要抛出EJBException即可。
setSessionContext()方法将会话的语境放到对象变量中,容器在结束会话Bean或自动超时死亡之前将会自动调用ejbRemove()方法,所以在此可以填入用来释放某些资源的代码。当实例被钝化或被激活时,调用ejbActivae()和ejbPassivate()方法,无状态会话Bean不会发生这些情况,在下一节将介绍。
一般情况下,习惯将组件实现类的命名规则规定为
EJB,所以我们把这个组件类起名为StatelessDateEJB 类StatelessDateEJB声明要实现SessionBean的定义,所以,对于StatelessDateEJB类,我们必须完全实现SessionBean的接口定义。
StatelessDateEJB.java代码:
|
假设我们保存到D:\ejb\StatelessDate\src\StatelessDateEJB .java
到此为止我们的Bean程序StatelessDate已经编写完毕了,使用如下命令进行编译:
下载本文示例代码专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean)专稿:实战EJB之二 开发会话Bean(无状态会话Bean) 给主人留下些什么吧!~~
|