stateful session bean和stateless session bean 的根本区别在于它们的生命周期不同,即有状态session bean会一直和固定的客户端保持会话, 即使被钝化;而无状态session bean则完全可以随时(当容器认为客户端结束了会话的时候)删除bean而不需要保持状态。为了验证容器处理两种bean的不同,下面写了一个简单的测试程序来测试。
测试工具及平台: Eclipse JAVA IDE, Sun Application Server 8.
一、首先编写好session bean:
1) 定义远程接口
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface Count extends EJBObject
... {
public int doCount() throws RemoteException;
}
2) 编写远程主接口
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface CountHome extends EJBHome
... {
public Count create() throws RemoteException,CreateException;
public Count create(int i) throws RemoteException,CreateException;
}
3) 编写session bean
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class CountBean implements SessionBean
... {
public int n=0;
public SessionContext ctxt;
public int doCount()
...{
n++;
return n;
}
public void ejbCreate() throws RemoteException,CreateException
...{
}
public void ejbCreate(int i) throws RemoteException,CreateException
...{
n=i;
}
public void ejbActivate() throws EJBException, RemoteException ...{
System.out.println("Bean"+n/10+" Acivated.");
}
public void ejbPassivate() throws EJBException, RemoteException ...{
System.out.println("Bean"+n/10+" Passvated");
}
public void ejbRemove() throws EJBException, RemoteException ...{
// TODO Auto-generated method stub
}
public void setSessionContext(SessionContext ctxt) throws EJBException,
RemoteException ...{
// TODO Auto-generated method stub
this.ctxt=ctxt;
}
}
以上便是运行在容器里的EJB程序。
二、部署这个bean
说明:为了测试有状态与无状态会话bean的不同,我们需要分别部署这两个bean。
启动了Sun Application Server 后需要分别进行部署,这里不说明具体过程。两个bean的部署描述文件为:
1) ejb-jar.xml:
< ejb-jar xmlns ="http://java.sun.com/xml/ns/j2ee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" version ="2.1" xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" >
< display-name > CountJar </ display-name >
< enterprise-beans >
< session >
< display-name > CountBean2 </ display-name >
< ejb-name > CountBean2 </ ejb-name >
< home > mybeans.CountHome </ home >
< remote > mybeans.Count </ remote >
< ejb-class > mybeans.CountBean </ ejb-class >
< session-type > Stateless </ session-type >
< transaction-type > Bean </ transaction-type >
< security-identity >
< use-caller-identity />
</ security-identity >
</ session >
< session >
< display-name > CountBean </ display-name >
< ejb-name > CountBean </ ejb-name >
< home > mybeans.CountHome </ home >
< remote > mybeans.Count </ remote >
< ejb-class > mybeans.CountBean </ ejb-class >
< session-type > Stateful </ session-type >
< transaction-type > Bean </ transaction-type >
< security-identity >
< use-caller-identity />
</ security-identity >
</ session >
</ enterprise-beans >
</ ejb-jar >
2) sun-ejb-jar.xml:
<! DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.1 EJB 2.1//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_2_1-1.dtd" >
< sun-ejb-jar >
< enterprise-beans >
< unique-id > 0 </ unique-id >
< ejb >
< ejb-name > CountBean </ ejb-name >
<jndi-name>CountBean</jndi-name>
< pass-by-reference > false </ pass-by-reference >
< is-read-only-bean > false </ is-read-only-bean >
< refresh-period-in-seconds > -1 </ refresh-period-in-seconds >
< cmt-timeout-in-seconds > 0 </ cmt-timeout-in-seconds >
< gen-classes />
</ ejb >
< ejb >
< ejb-name > CountBean2 </ ejb-name >
<jndi-name>CountBean2</jndi-name>
< pass-by-reference > false </ pass-by-reference >
< is-read-only-bean > false </ is-read-only-bean >
< refresh-period-in-seconds > -1 </ refresh-period-in-seconds >
< cmt-timeout-in-seconds > 0 </ cmt-timeout-in-seconds >
< gen-classes />
</ ejb >
</ enterprise-beans >
</ sun-ejb-jar >
注意黑体的部分
三、编写测试程序
测试程序主要思路是利用多线程技术启动3个测试bean,分别进行计数运算,通过观测结果可以得出本文的结论。
import mybeans. * ;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
public class TestCountClient
... {
public static void main(String args[])
throws Exception
...{
InitialContext ctxt=new InitialContext();
CountHome countHome=null;
countHome=(CountHome)PortableRemoteObject.narrow(ctxt.lookup("CountBean"), CountHome.class); //测试有状态会话bean
//countHome=(CountHome)PortableRemoteObject.narrow(ctxt.lookup("CountBean2"), CountHome.class); 测试无状态会话bean
Count count=countHome.create(1);
Count count2=countHome.create(2);
Count count3=countHome.create(3);
BeanThread t1=new BeanThread(1,count);
BeanThread t2=new BeanThread(2,count2);
BeanThread t3=new BeanThread(3,count3);
t1.start();
t2.start();
t3.start();
}
}
class BeanThread extends Thread
... {
public int n=0;
public Count count=null;
public BeanThread(int i, Count c)
...{
n=i;
count=c;
}
public void run()
...{
try...{
for (int i=0;i<10;i++)
...{
System.out.println("The current count"+n+" is: "+count.doCount());
Thread.sleep(10);
}
}
catch (Exception e)
...{
}
super.run();
}
public synchronized void start() ...{
// TODO Auto-generated method stub
super.start();
}
}
注意上面的程序,测试两种会话bean需要独立进行。即先注释化掉一种情况然后才能测试另一种。
四、测试结果
1) 测试有状态会话bean时得出的结果如(由于多线程特点,当然结果可能与下面不完全一致):
The current count2 is: 3
The current count3 is: 4
The current count1 is: 3
The current count3 is: 5
The current count2 is: 4
The current count1 is: 4
The current count2 is: 5
The current count1 is: 5
The current count3 is: 6
The current count1 is: 6
The current count3 is: 7
The current count2 is: 6
The current count1 is: 7
The current count3 is: 8
The current count1 is: 8
The current count2 is: 7
The current count1 is: 9
The current count3 is: 9
The current count2 is: 8
The current count3 is: 10
The current count1 is: 10
The current count3 is: 11
The current count2 is: 9
The current count1 is: 11
The current count3 is: 12
The current count2 is: 10
The current count3 is: 13
The current count2 is: 11
The current count2 is: 12
可以看到:上面的结果显示每个bean尽管执行交替进行,但是它们的状态还是保持的,即上次若是2,下次就是3。
2) 测试无状态会话bean时结果如下(当然也由于多线程的特点,结果很可能和下面不一致):
The current count1 is: 2
The current count2 is: 3
The current count2 is: 4
The current count3 is: 5
The current count1 is: 1
The current count2 is: 2
The current count1 is: 4
The current count3 is: 3
The current count1 is: 5
The current count2 is: 6
The current count3 is: 7
The current count1 is: 8
The current count2 is: 9
The current count2 is: 10
The current count3 is: 11
The current count1 is: 12
The current count2 is: 14
The current count1 is: 13
The current count3 is: 15
The current count2 is: 16
The current count3 is: 17
The current count1 is: 18
The current count2 is: 19
The current count1 is: 20
The current count3 is: 21
The current count2 is: 22
The current count3 is: 23
The current count1 is: 24
The current count3 is: 25
测试结果表明:无状态会话bean确实是无法保持会话状态的。但结果同时还显示了另外一个有趣的现象,即数字很大部分是累加的,这跟容器调度bean的算法是有关的。