一有状态会话 Bean 的开发和部署
基础知识
在第一节中我们给出了一个 HelloWorld 无状态的会话 Bean 在 EJB 规范中 EJB 包括三种 Bean 第一种便是会话 Bean(Session Bean) 然后还有实体 Bean(EntityBean) 和消息驱动 Bean
会话 Bean 包括无状态会话 Bean 和有状态会话 Bean 二者的主要区别是前者在执行的过程中不保存 Bean 的状态信息它没有状态域也就是说无状态会话 Bean 就只是一个执行过程我们调用它完成我们的任务而己它在容器池中无法保存 Bean 状态而后者在容器中执行时会保存 Bean 的执行状态相对应的有状态会话 Bean 中也对应有状态域即会话 Bean 在执行的过程中会将与固定客户端的会话状态保存起来以备后用
然而有状态会话 Bean 它没有主键类客户端无法查找出它对应的在容器池中的 EJBObject 那么我们如何重用我们的 EJBObject 呢?在这篇文章中我们提供了两种方法并给出了示例程序
第一种方法是采用有状态会话 Bean 的 Handle( 句柄 ) 为了取得句柄可以调用 EJBObject 接口的 getHandle ()方法返回一个 Handle 实例为了重新构建对同一 EJBObject 的引用可以使用 Handle 接口的 getEJBObject ()方法此方法返回一个对应 Handle 的 EJB 对象利用此对象我们就可以重构出对应的 EJBObject 如下示例
Count count = counthomecreate();// 产生 Remote 接口对象
javaxejbHandle handle = countgetHandle();// 获得 Remote 接口的句柄
…
Object obj = handlegetEJBObject();// 得获得 Handle 对应的在容器池中的 EJBObject 对象
Count recount= (Count)PortableRemoteObjectnarrow(objCountclass);
// 将此对象重构为远程接口对象即可重新调用它的方法
第二种方法是采用有状态会话 Bean 的 HomeHandle 它类似 handle 但不能用于引用 EJBObject HomeHandle 包含足够的信息可以重建 EJBHome ()的引用它的做法是调用 getHomeHandle ()方法 和 getEJBHome ()方法此方法返回一个对应 Handle 的 EJBHome 对象利用此对象可以重新生成出对应的 EJBObject 对象然后调用它的方法如下示例
Content ctx = new InitialContext();
Object h = ctxlookup(CountHome);
CountHome home = (CountHome)PortableRemoteObjectnarrow(h CountHomeclass);
HomeHandle homehandle = homegetHomeHandle();// 获取 HomeHandle
CountHome reHome = (CountHome)homeHandlegetEJBHome();
Count recount = rehomecreate();
利用以上两种方法我们可以自动的存储并重建引用所需的会话 Bean 中的 EJB 信息
好了了解了以上知识下面我们就来一个真实的会话 Bean 来看看它的运行方式!
一个有状态会话Bean的开发和部署
开发一个会话 Bean 基本的应遵守以下步聚首先开发 Remote 接口再编写 Home 接口然后是 Bean 本身
同时为了区别我们应默认遵守以下命名规则 Remote 接口直接用 xxx 命名 Home 接口用 xxxHome 命名 Bean 本身用 xxxBean 命名
首先我们手动建立开发环境在 C:\JBOSS 目录(这里指 JBOSS 的安装目录详见上一节)下新建一个存放我们项目的目录 myproject 然后再在 myproject 下建一个存放此 Count 会话 Bean 的目录 CounterStatefullSessionBean 用来存放我们的这个 Bean 的所有相关文件然后再在 CounterStatefullSessionBean 目录下建三个目录 ejb jsp 和 src 分别用来存放 ejb 类 Web 应用文件( jsp 文件及 Servlet 类)和我们的源程序
接着再在 EJB 目录下建一个 client 目录和一个 counterjar 目录分别用来存放 client 端测试程序和服务器端类然后再在 client 和 counterjar 目录下同时各新建一个 counter 目录 counter 目录下再建一个 ejb 目录这是我们的包名然后在 counterjar 目录下再建一个 METAINF 目录用于存放我们的 ejb 配置文件
接着再在 jsp 目录中新建一个 counterwar 目录用于保存 WEB 发部的程序再在 counterwar 下新建一个 WEBINF 目录同时在 WEBINF 目录中新建一个 classes 目录其下面再建包目录 counter 及 counter 目录下的 ejb 目录
好了我们的目录己建立成功我们的目录结构见图 所示
图 好了我们利用上面的知识来建一个有状态会话 Bean 及它的测试程序我们在这里引入《 Mastering EJB 》 (Second Edition) 中的一个会话 Bean 即 Count 这个 Bean 中有一个状态域命名为 val 它用来保存相应客户端调用 EBJ 方法 count 的次数
我们进入 src 目录所有的类源程序我们都在此目录中编写和存放
编写 Remote 接口代码如下
//Countjava
package counterejb;
import javaxejb*;
import javarmiRemoteException;
public interface Count extends EJBObject{
public int count() throws RemoteException;
}
编写 Home 接口代码如下
//CountHomejava
package counterejb;
import javaxejb*;
import javarmiRemoteException;
public interface CountHome extends EJBHome{
Count create(int val) throws RemoteExceptionCreateException;
}
编写 Bean 类代码如下
//CountBeanjava
package counterejb;
import javaxejb*;
public class CountBean implements SessionBean{
// 当前的计数值就是对话状态
public int val;
private SessionContext ctx;
//EJB 方法
public int count(){
Systemoutprintln(count());
return ++val;
}
//EJB 必须的方法
public void ejbCreate(int val) throws CreateException{
thisval=val;
Systemoutprintln(ejbCreate());
}
public void ejbRemove(){
Systemoutprintln(ejbRemove());
}
public void ejbActivate(){
Systemoutprintln(ejbActivate());
}
public void ejbPassivate(){
Systemoutprintln(ejbPassivate());
}
public void setSessionContext(SessionContext ctx){
thisctx = ctx;
}
public SessionContext getSessionContext(){
return thisctx;
}}
好了我们在 src 目录中产生了三个 java 文件这是 EJB 必须的类下面我们用在第一节中编写的 combat 文件来编译它们
进行 src 目录热行 com *java 即会产生三个 class 文件
下面我们部署我们的 EJB 首先编写部署描述符进入
C \JBOSS\myproject\CounterStatefullSessionBean\ejb\counterjar\METAINF 目录中新建一个 ejbjarxml 文件内容如下
<?xml version= encoding=gb?>
<!DOCTYPE ejbjar PUBLIC //Sun Microsystems Inc//DTD Enterprise JavaBeans //EN
jar__dtd>
<ejbjar>
<enterprisebeans>
<session>
<displayname>Count</displayname>
<ejbname>Count</ejbname>
<home>counterejbCountHome</home>
<remote>counterejbCount</remote>
<ejbclass>counterejbCountBean</ejbclass>
<sessiontype>Stateful</sessiontype>
<transactiontype>Container</transactiontype>
</session>
</enterprisebeans>
</ejbjar>
此为 EJB 布署描述符文件它里声明了此 CountBean 的一些属性如声明了本地接口远程接口及 Bean 的类型其中 <sessiontype>Stateful</sessiontype> 一句声明此 Bean 是有状态会话 Bean 如果是无状态会话 Bean( 见第一节中的 HelloWorld) 则此处应该是 Stateless
然后我们再在此目录中新建一个 jbossservicexml 文件它是 JBOSS 服务器特有的描述文件它的内容如下
<?xml version= encoding=gb?>
<jboss>
<enterprisebeans>
<session>
<ejbname>Count</e