您的位置:首页 > 其它

有状态会话bean与无状态会话Bean的区别

2013-08-06 11:49 225 查看
有状态会话Bean和无状态会话Bean的区别

状态通常理解为对象的属性,那么无状态就是没有属性,有状态就是有属性,这种理解是不正确的。

这里的无状态确实与属于相关,但有状态会话Bean和无状态会话Bean之间的区别并不是是否有属性,而是是否保存客户端的属性。有状态会话Bean会保存客户端的状态,而无状态Bean不会专门保存客户端的状态。这里需要强调“专门”是因为无状态会话Bean也会有成员变量,有成员变量就可以保存状态,但它不会专门为特定的客户端保存状态。

区别的根本原因

这与无状态会话Bean和有状态会话Bean的运行原理是相关的。

对于有状态会话Bean来说,只要有客户端发送对有状态会话Bean的访问,服务器都会创建一个会话Bean实例与该客户端对应,这样这个实例与这个客户端就是一一对应的。如果客户端在Bean实例中保存了信息,之后还可以使用。

对于无状态会话Bean来说,服务器端会维持一个实例池,创建好若干个实例对象供客户端调用。当从客户端发送创建会话Bean的请求时,并不一定会真的创建EJB,多数情况下是从实例池中得到一个实例,用完之后重新放回实例池。如果下次再访问,再从实例池中取出一个实例使用,并不一定是上次的实例。即使两次访问使用的是同一个实例,在两次访问之间也有可能有其他的客户端访问了该实例。所以,并不能保证在多次访问之间的信息会被保存。所以,无状态会话Bean不会专门保存客户端的信息。

各自的优缺点

因为有状态会话Bean需要保存特定客户端的信息,一个客户端对应一个实例,既是在当时客户端有连接没有访问的情况下,也要为这个客户端保留这个实例。这样随着客户端数量的增加,服务器端需要创建的实例的数量也在增加,增加到一次程度对服务器的性能就会有一定的影响。为了不对服务器的性能产生影响,通常服务器会进行一些优化。当客户端的数量超过某个值之后,就不创建新的实例。虽然不创建新的实例,还是需要对用户响应,这时候就采用共享实例的方式。会查看哪个实例虽然处于连接状态,但是没有访问,然后把这个实例的状态保存起来,使用这个实例为新的请求服务,对于原来的客户端来说,称为挂起。如果原来的客户端又发送请求了,会重新查找一个空闲的实例并且把已经保存好的状态恢复回来,这个过程称为激活。所以在有状态会话Bean的访问过程,经常会发生查找实例,激活挂起等操作,所以效率比较低。

而发送对无状态会话Bean的请求的时候,可以随便取一个空闲的实例为客户端服务,所以效率比较高。

有状态会话Bean的好处是,可以保存客户端的状态,所以客户端在后续访问的时候就可以少传递一些参数。而状态会话Bean需要传递方法执行过程中需要的所有参数。

如何选择

根据上面分析的有状态会话Bean和无状态会话Bean的优缺点。如果要频繁的访问,并且多次访问之间会共享一些信息,这时候应该使用有状态会话Bean。对于不经常使用的功能,可以使用无状态会话Bean。无状态会话Bean的使用要比有状态会话Bean的使用多。

一个描述无状态会话Bean和有状态会话Bean区别的实例

下面的代码是一个表示购物车的有状态会话Bean:

package ch19;

import javax.ejb.Stateful;

import java.util.List;

@Stateful

public class CartBean implements Cart{

private String customerId;

private String customerName;

private ArrayList<String> contents;

public void initialize(String person) throws BookException {

if (person == null) {

throw new BookException("不允许没有用户!");

} else {

customerName = person;

}

customerId = "0";

contents = new ArrayList<String>();

}

public void initialize(String person, String id)

throws BookException {

if (person == null) {

throw new BookException("不允许没有用户!");

} else {

customerName = person;

}

IdVerifier idChecker = new IdVerifier();

if (idChecker.validate(id)) {

customerId = id;

} else {

throw new BookException("无效的ID: " + id);

}

contents = new ArrayList<String>();

}

public void addBook(String title) {

contents.add(title);

}

public void removeBook(String title) throws BookException {

boolean result = contents.remove(title);

if (result == false) {

throw new BookException(title + " 不在购物车中。");

}

}

public List<String> getContents() {

return contents;

}

@Remove()

public void remove() {

contents = null;

}

}

假设业务接口是Cart

代码来源:《Java EE 5实用教程——基于WebLogic和Eclipse》

如果在客户端注入两个EJB对象,通过实例注入,代码如下:

@EJB

Cart cart1;

@EJB

Cart cart2;

调用业务方法的代码如下:

cart1.initialize(“张三”);

cart1.addBook(“JSP2.0基础教程”);

cart1.addBook(“Java EE5实用教程”);

cart2.initialize(“李四”);

cart2.addBook(“ASP网站开发”);

cart2.addBook(“最新C#实例开发”);

List<String> books=cart1.getContents();

out.println(“cart1中的图书为:”);

for(int i=0;i<books.size();i++){

out.println(books.get(i));

}

books=cart2.getContents();

out.println(“<br>cart2中的图书为:”);

for(int i=0;i<books.size();i++){

out.println(books.get(i));

}

执行的结果如下:

cart1中的图书为:JSP2.0基础教程 Java EE5实用教程

cart2中的图书为:ASP网站开发 最新C#实例开发

如果把CartBean中的Stateful改成Stateless,重新运行会得到下面的执行结果:

cart1中的图书为:ASP网站开发 最新C#实例开发

cart2中的图书为:ASP网站开发 最新C#实例开发

为什么两次的结果不相同呢?有状态会话Bean的使用cart1和cart2对应两个Bean实例,各自有各自的属性。而在无状态会话Bean中,cart1和cart2实际上对应的是同一个Bean实例,所以通过cart1添加的图书被cart2的添加操作给覆盖了,所以最后cart1得到的图书不再是存放进去的“Java Web程序设计基础教程”和“Java EE 5实用教程”。通过这个实例可以更好的理解又状态会话Bean和无状体会话Bean的区别。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: