首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

<转>EJB 对话Bean的理解

2012-10-08 
转EJB 会话Bean的理解会话Bean(Session Bean)是EJB三种企业Bean中的一种,另外两种是消息Bean和实体Bean,

<转>EJB 会话Bean的理解

会话Bean(Session Bean)是EJB三种企业Bean中的一种,另外两种是消息Bean和实体Bean,会话Bean主要用来封装业务逻辑,提供业务服务。

会话Bean又分为两种,一种是有状态的(Stateful,简称SFSB),一种是无状态的(Stateless,简称SLSB),它们都能提供本地接口和远程接口,本地接口指所提供的业务接口只能由同一Java EE服务中的程序所访问,它们都是在同一JVM当中;远程接口指所提供的业务接口可以被远程的程序访问,通常都是在不同的JVM中(可以是同一机器,也可以是不同的机器),当然在本地(同一Java EE服务器)也可以访问远程接口,就像访问本地接口一样,因为它们在同一JVM当中。不管是在本地接口还是远程接口,其实都是通过JNDI访问,只不过本地接口或者同一JVM当中的JNDI访问要简单的多,因为JBoss为我们处理了,而远程接口的JNDI访问需要使用RMI,这就是其它话题了,这里只是说在同一JBoss中访问远程接口就跟访问本地接口一样

有状态与无状态的区别在于对状态的处理上(废话),这里的状态指会话Bean实例的状态,处理的不同在于:


有状态Bean中的状态可以一直保存,直到你销毁它,这个过程中可能JBoss或者机器重启过,但这个状态一直存在,这是通过把Bean实例纯化到硬盘实现(序列化写入一个文件);无状态Bean当Jboss重启后,它将不在存在,也有可能在JBoss的运行过程中就被垃圾回收销毁了。有状态的Bean也有可能被垃圾回收,但在这之前,它的状态肯定会被纯化保存



既然状态就是会话Bean的实例,那么状态的保存其实就表示一直使用的都是同一个有状态会话Bean(应该说可以看作一直使用的都是同一个Bean实例,因为纯化后再被激活可能就是创建新的对象了,但这不影响状态的保存,只是一个对象实例被序列化到文件,激活后又恢复而已,说多了),而无状态Bean其实就表示你第一次使用的是一个无状态Bean的实例,第二次你调用时可能就是另外一个实例,虽然它们是同一个接口,但你两次调用的可能就不是同一个对象,这里说的可能,也就是说你也有可能两次调用的还是同一个接口的同一个实例,这取决于实际情况(也就是实例池的情况),但对于有状态来说,这两次调用的就是同一个接口的同一个实例(其实这个说法是不完全正确的,要看你怎么调用有状态的Bean,后面再讨论)

JBoss有一个对象实例池,其中保存有创建的会话Bean的实例,EJB是单线程编程模型(现在看来实例池与单线程模型是EJB最受争议的地方,因为单线程模型导致EJB的编码是过程化的,一些OOP的方法在这里不能被很好的使用,这个后面有讨论)。
?

一个会话Bean的实例只能同时服务于一个线程,而且在会话Bean中是不能创建线程的。对于一个接口请求,JBoss会为它创建一个线程,该线程一直持续到对JBoss的请求访问结束(我们可以通过这个线程的名字来得到客户端的ip,请看这里:怎么得到访问JBOSS的客户端IP地址),在该请求过程中所访问的其它会话bean都在该线程中执行。如果一个会话Bean被一个线程使用了,就不能同时被另一个线程使用。只有会话Bean重新放回到实例池中后,才可以被其它的线程使用


对于无状态的会话Bean,如果请求的Bean在实例池中有空闲的,那么就用之,如果实例池是没有空闲的Bean,并且实例池允许保存的实例数量没有被用完,则创建之,用完后放回实例池。如果实例池已经被占满了,那么JBoss会垃圾回收一些Bean的实例(回收原则可能是LRU,猜的),如果是无状态的,直接回收,如果是有状态的,先纯化它,再回收,这就是有状态和无状态的区别。
所以对于无状态的会话Bean就会出现上面说的情况,你这次请求的Bean,服务完你后,被放回到实例池中,你下次再请求时这个Bean可能被其它请求使用了,或者被垃圾回收了,服务你的将是另一个Bean实例。

对于有状态的会话Bean,状态怎么保存上面已经说了:序列化为一个文件。那么状态怎么共享呢?也就是同一个状态在不同的请求间如何共享的,如果不能共享,状态保持也没什么用处。举个常见的例子:购物车。用户会选择不同的商品放到购物车中,这个状态体现在:不管用户跑到那个页面去鬼混,回来后购物车中的商品还在;用户可能关掉电脑出去鬼混了,但他回来重新打开电脑后,商品也应该还在。这里如果使用有状态的会话Bean来实现购物车,放置商品和保持商品都不困难。问题在于,用户离开了购物车去浏览其它页面,回来后,怎么知道这个用户的状态保存在那个有状态会话Bean里面(上面说了,Bean有个实例池,里面有很多的Bean实例)?这是Java EE服务器为我们绑定用户与SFSB的关系吗?是SFSB自己知道访问它的是那个用户吗?都不是,
?

Java EE服务器及SFSB本身不知道保存的会话状态是那个会话的。你要在两次请求间共享同一个SFSB的话,应用自己(其实就是指开发者了)要指定两次请求时访问的SFSB为同一个,也就是同一们对象引用,这样才能在两次请求间共享同一个保存的会话状态,例如可以把SFSB的引用保存在HTTP Session。如果不自己指定访问的SFSB是那个,那么同一个用户两次请求可能就创建了两个SFSB了。也就是说SFSB的状态与应用上的会话之间的关联关系得靠开发者自己控制,SFSB只会负责保存自己的状态(上面说了,就是把自己当前的实例状态序列化成一个文件)

当然,上面说了,Bean是线程模型的,一个Bean只能同时被一个线程使用,所以同一个请求线程中的SFSB其实就是同一个了,同一个请求间状态肯定是共享的(这个应该中EJB 容器处理的SFSB的实例一直归这个线程所有,直到线程结束,但不知道SLSB是不是这样,也是线程结束后放回到实例池呢,还是说调用结束就放回实例池,既然是SLSB,我想应该是后者)。上面说的要保存引用指的是两次不同的请求,比如用户关闭了电脑出去鬼混后,再回来请求购物车,这时应用就要知道这个人之前使用的是那个SFSB的实例,现在要恢复使用它了(可能是从实例池中拿出,也有可能是从纯化的文件中激活)

所以有状态和无状态只是说对Bean实例的对待不同:一个Bean实例会被纯化保存,一个不会。其它都一样的,它们都可以定义对象的成员变量(属性),并且对于SLSB,这个对象属性可能会被不同的调用者访问到。其它都是一样的,它们都会被放到实例池中,SLSB放回实例池中以便再次提供服务,SFSB也会放到实例池中,因为状态可能被再次用到,总不至于每次都是用完就纯化保存吧,纯化,激活时的文件读写的开销也是EJB受争议的地方:如果实例池满了,SFSB多的话,EJB容器可能会不断的纯化-激活-纯化-激活SFSB。

热点排行