【EJB2+JBOSS】Stateless Bean和Stateful Bean

    在学习EJB的时候,我们知道,EJB里面有stateless(无状态)bean和stateful(有状态)bean,有状态bean和无状态bean到底有什么特性呢,今天我们来探讨一下这两种bean的区别。

    Stateless Bean,也叫做无状态会话bean。顾名思义,这种bean只为用户提供操作,不负责保存用户的状态。所以任何用户都可以调用,一般情况下,无状态bean会存在于对象池中,用户调用时,从中取出实例进行操作,当用户操作完毕时,bean会重新回到对象池中(这里特别要注意,即使调用它的用户不存在了,bean也有可能存在)也就是说,如果无状态会话bean中有成员变量的话,这个变量会受到所有可能调用它的用户的影响。

    下面我们看一个有成员变量的stateless bean的例子:

    Interface:

    

package org.chou.mickey.servers.demo;

public interface StatelessBeanService {
    public void addOne();
	
    public int getCount();
}

    stateless bean:

package org.chou.mickey.servers.impl.demo;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import org.apache.log4j.Logger;
import org.chou.mickey.servers.demo.StatelessBeanService;

@Stateless
@Remote(StatelessBeanService.class)
public class StatelessBeanServiceImpl implements StatelessBeanService {
    public static final String CLASS_NAME = StatelessBeanServiceImpl.class.getName();
	
    public static Logger logger = Logger.getLogger(StatelessBeanServiceImpl.class);
	
    private int count = 0;
	
    public void addOne() {
	String methodName = "addOne";
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " Start >>>>>");
	count++;
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " End >>>>>");
    }
	
    public int getCount() {
	String methodName = "getCount";
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " Start >>>>>");
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " End >>>>>");
	return count;
    }
}

    调用EJB代码:

    

package org.chou.movie.actions;

import javax.naming.InitialContext;

import org.apache.log4j.Logger;
import org.chou.mickey.servers.demo.StatelessBeanService;
import org.chou.movie.utils.InitialContextCreater;

import com.opensymphony.xwork2.ActionSupport;

public class TestStatelessAction extends ActionSupport {

    private static final long serialVersionUID = 2218164559073115228L;
	
    private static final String CLASS_NAME = TestStatelessAction.class.getName();
	
    private static Logger logger = Logger.getLogger(TestStatelessAction.class);
	
    public String execute() throws Exception {
        String methodName = "execute";
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + "Start >>>>>");
		
	InitialContext context = InitialContextCreater.getInitialContext();
	StatelessBeanService service = (StatelessBeanService)context.lookup("StatelessBeanServiceImpl/remote");
		
	service.addOne();
	int count = service.getCount();
		
	logger.info("☆☆☆☆☆ count = " + count);
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + "Start >>>>>");
		
	return ActionSupport.SUCCESS;
    }
}
   我们在第1次调用时打印如下:

2014-11-18 21:09:03  INFO TestStatelessAction:execute:21 - <<<<< org.chou.movie.actions.TestStatelessAction executeStart >>>>>
2014-11-18 21:09:04  INFO TestStatelessAction:execute:29 - ☆☆☆☆☆ count = 1
2014-11-18 21:09:04  INFO TestStatelessAction:execute:30 - <<<<< org.chou.movie.actions.TestStatelessAction executeStart >>>>>
    第二次调用:

2014-11-18 21:10:41  INFO TestStatelessAction:execute:21 - <<<<< org.chou.movie.actions.TestStatelessAction executeStart >>>>>
2014-11-18 21:10:41  INFO TestStatelessAction:execute:29 - ☆☆☆☆☆ count = 2
2014-11-18 21:10:41  INFO TestStatelessAction:execute:30 - <<<<< org.chou.movie.actions.TestStatelessAction executeStart >>>>>
     我们换个浏览器继续进行第三次调用(换个浏览器相当于我们切换到了另一个用户来调用):

2014-11-18 21:12:33  INFO TestStatelessAction:execute:21 - <<<<< org.chou.movie.actions.TestStatelessAction executeStart >>>>>
2014-11-18 21:12:33  INFO TestStatelessAction:execute:29 - ☆☆☆☆☆ count = 3
2014-11-18 21:12:33  INFO TestStatelessAction:execute:30 - <<<<< org.chou.movie.actions.TestStatelessAction executeStart >>>>>
     看到这些打印的结果,我们能想到什么呢?三次调用,调用的是同一个实例,即使我们切换了用户,也无法改变。 这充分说明,一个stateless bean的实例,可能被多个用户进行多次调用。根据上面所说的stateless bean的特性,我们可以知道,每次调用完后,bean实例会回到对象池中,等待下一次调用。第一次调用的时候,count+1=1;第二次调用count+1=2,第三次调用count+1=3。这也印证了,statelss bean中的状态,会被多个用户影响,而不是单纯的只记录一个用户的状态;这也就是stateless bean无法负责保存用户状态信息的原因,因为它无法在其生命周期中保证只为一个用户负责。


    接下来我们看看stateful bean:

    stateful bean,也叫状态会话bean。从名字就可以看出,状态会话bean不但可以为用户提供操作,还可以保存一个用户的状态。状态会话bean会为每一个用户创建一个实例,在一个状态会话bean实例的生命周期中,它只为一个用户服务,所以,它能够保存用户的状态。

    在使用会话状态bean的过程中,每次我们lookup时,都会创建一个新的bean实例,如果希望一直使用某个状态bean的实例,我们可以在操作完后,将其存入客户端中,下次使用的时候再取出来使用即可。而且,你不用担心别的用户会影响到这个bean的状态。它只归一个用户所有。

     OK,我们下面来看一个状态会话bean的实例:

     interface:

package org.chou.mickey.servers.demo;

public interface StatefulBeanService {
    public void addOne();
    public int getCount();
}
      stateful bean:

package org.chou.mickey.servers.impl.demo;

import javax.ejb.Remote;
import javax.ejb.Stateful;
import org.apache.log4j.Logger;
import org.chou.mickey.servers.demo.StatefulBeanService;
import org.chou.mickey.servers.demo.StatelessBeanService;

@Stateful
@Remote(StatefulBeanService.class)
public class StatefulBeanServiceImpl implements StatelessBeanService {
    public static final String CLASS_NAME = StatefulBeanServiceImpl.class.getName();
	
    public static Logger logger = Logger.getLogger(StatefulBeanServiceImpl.class);
	
    private int count = 0;
	
    public void addOne() {
	String methodName = "addOne";
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " Start >>>>>");
	count++;
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " End >>>>>");
    }
	
    public int getCount() {
	String methodName = "getCount";
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " Start >>>>>");
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + " End >>>>>");
	return count;
    }
}
    调用stateful bean:

package org.chou.movie.actions;

import java.util.Map;
import javax.naming.InitialContext;
import org.apache.log4j.Logger;
import org.apache.struts2.interceptor.SessionAware;
import org.chou.mickey.servers.demo.StatefulBeanService;
import org.chou.movie.utils.InitialContextCreater;
import com.opensymphony.xwork2.ActionSupport;

public class TestStatefulAction extends ActionSupport implements SessionAware{

    private static final long serialVersionUID = 2218164559073115228L;
	
    private static final String CLASS_NAME = TestStatefulAction.class.getName();
	
    private static Logger logger = Logger.getLogger(TestStatefulAction.class);
	
    private Map<String, Object> session;
	
    public String execute() throws Exception {
	String methodName = "execute";
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + "Start >>>>>");
		
	InitialContext context = InitialContextCreater.getInitialContext();
	StatefulBeanService service = (StatefulBeanService)session.get("Count");
	if ( service == null ) {
	    service = (StatefulBeanService)context.lookup("StatefulBeanServiceImpl/remote");
	}
		
	service.addOne();
	session.put("Count", service);
	int count = service.getCount();
		
	logger.info("☆☆☆☆☆ count = " + count);
	logger.info("<<<<< " + CLASS_NAME + " " + methodName + "Start >>>>>");
		
	return ActionSupport.SUCCESS;
    }
    public void setSession(Map<String, Object> session) {
	this.session = session;
    }
}
    执行第一次调用结果:

2014-11-18 21:32:27  INFO TestStatefulAction:execute:23 - <<<<< org.chou.movie.actions.TestStatefulAction executeStart >>>>>
2014-11-18 21:32:28  INFO TestStatefulAction:execute:35 - ☆☆☆☆☆ count = 1
2014-11-18 21:32:28  INFO TestStatefulAction:execute:36 - <<<<< org.chou.movie.actions.TestStatefulAction executeStart >>>>>
     同浏览器第二次调用结果:

2014-11-18 21:33:20  INFO TestStatefulAction:execute:23 - <<<<< org.chou.movie.actions.TestStatefulAction executeStart >>>>>
2014-11-18 21:33:20  INFO TestStatefulAction:execute:35 - ☆☆☆☆☆ count = 2
2014-11-18 21:33:20  INFO TestStatefulAction:execute:36 - <<<<< org.chou.movie.actions.TestStatefulAction executeStart >>>>>
     不同浏览器第三次调用结果:

2014-11-18 21:34:05  INFO TestStatefulAction:execute:23 - <<<<< org.chou.movie.actions.TestStatefulAction executeStart >>>>>
2014-11-18 21:34:05  INFO TestStatefulAction:execute:35 - ☆☆☆☆☆ count = 1
2014-11-18 21:34:05  INFO TestStatefulAction:execute:36 - <<<<< org.chou.movie.actions.TestStatefulAction executeStart >>>>>
     仔细看看,我们上面执行产生的结果,当第一次,第二次同浏览器调用时,调用的是同一个stateful bean的实例,第三次,换个浏览器调用时,调用的是另一个stateful bean的实例,这就验证了,stateful bean会为每一个用户创造一个实例,而他们之间不会互相影响,从而使stateful bean可以为用户的状态负责。

     细心的童鞋也许会看到,我们在action中调用stateful bean时,和stateless bean稍微有点不一样。调用stateless bean时,直接用lookup进行查找。而调用stateful bean时,我们首先在session里面取,如果取不到,我们才用lookup进行查找,这就是我们所说的,如果想一直使用同一个stateful bean实例,要把它存在客户端。否则,按照stateful bean的性格,你直接查找,它会直接产生一个新的实例,那么之前的状态还是丢失了,无法在程序里面传递。要想在程序里面传递stateful bean的状态,就要按照这种方法进行调用。当然,如果在同一个用户里你不想要它的状态了,你也可以向stateless bean一样,直接lookup,它会给你一个崭新的实例。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值