stateful session bean和stateless session bean 的根本区别在于它们的生命周期不同,即有状态session bean会一直和固定的客户端保持会话, 即使被钝化;而无状态session bean则完全可以随时(当容器认为客户端结束了会话的时候)删除bean而不需要保持状态。为了验证容器处理两种bean的不同,下面写了一个简单的测试程序来测试。
测试工具及平台: Eclipse JAVA IDE, Sun Application Server 8.
一、首先编写好session bean:
1) 定义远程接口
package
mybeans;
import
java.rmi.RemoteException;
import
javax.ejb.EJBObject;
public
interface
Count
extends
EJBObject
...
{ public int doCount() throws RemoteException; }
2) 编写远程主接口
package
mybeans;
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
package
mybeans;
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:
<?
xml version="1.0" encoding="UTF-8"
?>
<
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:
<?
xml version="1.0" encoding="UTF-8"
?>
<!
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,分别进行计数运算,通过观测结果可以得出本文的结论。
package
client;
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 count1 is: 2 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 count3 is:
1
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的算法是有关的。