Ejb-有状态&无状态SessionBean

1.    Ejb的分类

  首先,企业级Bean分为三类:


  技术分享


  SessionBean用于实现业务逻辑,它可以是有状态的,也可以是无状态的。每当客户端请求时,容器就会选择一个SessionBean来为客户端服务。SessionBean可以直接访问数据库,但更多时候,它会通过EntityBean实现数据访问。

  Entity Bean是域模型对象(用来表示真实世界的实体),用于实现O/R映射,负责将数据库中的表记录映射为内存中的Entity对象,事实上,创建一个Entity Bean对象相当于新建一条记录,删除一个Entity Bean会同时从数据库中删除对应记录,修改一个Entity Bean时,容器会自动将EntityBean的状态和数据库同步。

  MessageDriven Bean是EJB2.0中引入的新的企业Bean,它基于JMS消息,只能接收客户端发送的JMS消息然后处理。MDB实际上是一个异步的无状态SessionBean,客户端调用MDB后无需等待,立刻返回,MDB将异步处理客户请求。这适合于需要异步处理请求的场合,比如订单处理,这样就能避免客户端长时间的等待一个方法调用直到返回结果。

下面主要介绍三种Ejb中的SessionBean:


2.    SessionBean


  2.1  概念

       首先,会话Bean可以执行业务逻辑操作,比如注册用户、订单登记、数据库操作等。

从客户端获得EJB对象开始,然后调用EJB的方法(可以多次),直到客户端生命周期结束,或客户端释放了EJB对象为止,称为一次会话。随着会话的终止,EJB对象也有可能会被EJB容器销毁。如下图:


  技术分享


  如上图,客户端与服务器完成了两次会话。


  2.2 对象的状态

  对象的状态是由其实例变量(即成员变量)的值组成的,这里要区别“实例变量”与“类变量”的概念。实例变量即与实例相关的变量,为非静态变量;类变量,当然就是类相关的变量,一般为静态变量。如下图:


  技术分享


  感觉对象的实例变量,即我们通常说的类的普通(非静态、全局)属性。如果一个类的多个对象,可以区分开,那么就说是有状态的;反之,如果一个类的多个对象,是无法区分开的,那么就说是无状态的。


  2.3 有状态SessionBean

       即Ejb能够为同一个客户端在多次请求(方法调用)之间保持状态信息。如果要实现购物车功能,类似HttpSession对象,那么Ejb必须能够区分不同的客户端,并分别为不同的客户端保持与之对应的状态信息。

       或,从某个客户端的角度来看,似乎Ejb对象正被它独占了一样,不会因为有任何其它的客户端同时对同一个Ejb访问而影响其最终的计算结果。

  类似购物过程中,客户端与HTTPSESSION的交互过程,如下图:


  技术分享


  然后看Stateful SessionBean的原理:


  技术分享


 

  2.4 无状态SessionBean

  并非是说EJB不能存在状态,而是说EJB容器不会对EJB的状态做管理。

  容器会使用实例池的方式,甚至单例的方式来实现无状态的Session Bean。因为EJB容器不会对Stateless Session Bean的状态进行管理,所以它的性能要比Stateful Session Bean的好。


  2.5 Spring中的相关配置

  由Spring管理的业务逻辑类,是无状态的(Singleton):


  技术分享


  Struts2中的Action,是有状态的(prototype):

  技术分享


3.    实例代码


  3.1 有状态SessionBean

  服务端-接口

public interface StatefulEjb {
	public void compute(int i);

	public int getResult();
}

  服务端-实现

import javax.ejb.Remote;

import com.sun.xml.internal.ws.developer.Stateful;

@Stateful
@Remote
public class StatefulEjbBean implements StatefulEjb {
	private int state;

	public void compute(int i) {
		state = state + i;
	}

	public int getResult() {
		return state;
	}
}

  客户端:

import javax.naming.InitialContext;

public class StatefulEjbClient {
	public static void main(String[] args) throws Exception {
		InitialContext context = new InitialContext();
		StatefulEjb ejb1 = (StatefulEjb) context
				.lookup("StatefulEjbBean/remote");
		System.out.println(ejb1.getResult());
		ejb1.compute(1);
		System.out.println(ejb1.getResult());//输出1
		ejb1.compute(1);

		StatefulEjb ejb2 = (StatefulEjb) context
				.lookup("StatefulEjbBean/remote");
		System.out.println(ejb1.getResult());//接着上面,所以输出2
		ejb1.compute(1);
		System.out.println(ejb1.getResult());
	}

}

  3.2 无状态SessionBean

  服务端-接口

public interface StatelessEjb {
	public void compute(int i);

	public int getResult();
}

  服务端-实现

import javax.ejb.Remote;
import javax.ejb.Stateless;

@Stateless
@Remote
public class StatelessEjbBean implements StatelessEjb {
	private int state;

	public void compute(int i) {
		state = state + i;
	}

	public int getResult() {
		return state;
	}

}

  客户端

import javax.naming.InitialContext;

public class StatelessEjbClient {
	public static void main(String[] args) throws Exception {
		InitialContext context = new InitialContext();
		StatelessEjb ejb1 = (StatelessEjb) context
				.lookup("StatelessEjb/remote");
		System.out.println(ejb1.getResult());
		ejb1.compute(1);
		System.out.println(ejb1.getResult());//输出【1】
		ejb1.compute(1);

		StatelessEjb ejb2 = (StatelessEjb) context
				.lookup("StatelessEjb/remote");
		System.out.println(ejb1.getResult());//不会接着上面的值,所以输出为【0】
		ejb1.compute(1);
		System.out.println(ejb1.getResult());
	}
}

4.    总结

       可以看到,有状态的SessionBean在两次请求之间,保存了客户端状态的值;而无状态的SessionBean并非是说EJB不能存在状态,而是说EJB容器不会对EJB的状态做管理。

       有状态SessionBean,为了区分不同的对象,容器就每次都新创建对象;无状态SessionBean,为了提高效率(复用),容器一般只创建一次【单例】,或创建一个实例池。

文章来自:http://blog.csdn.net/wang379275614/article/details/43818335
© 2021 jiaocheng.bubufx.com  联系我们
ICP备案:鲁ICP备09046678号-3