首页 > 代码库 > EJB初级篇--EJB组件之会话Bean
EJB初级篇--EJB组件之会话Bean
上篇博文中我们已经详解介绍了什么是EJB。其实最简单的说:EJB就是运行在独立服务器上的组件,客户端是通过网络对EJB对象进行调用的。而我们常说的企业Bean组件可以分为三种类型:会话Bean、消息驱动Bean和实体Bean。依据应用设计的不同,开发者可以选择适合应用的组件类型。下面几篇博文中我会为大家分别详细的介绍这三种企业Bean组件。本篇博文则就先来介绍介绍会话Bean吧。
首先来介绍一下,什么是会话Bean。会话Bean能够完成客户所要求的业务操作,它是含有业务逻辑的可重用组件,并能够用于业务过程。简单一句话:会话Bean就是用来实现业务逻辑的。
下面就详细介绍会话Bean的主要内容,包括以下两点:一是会话Bean的生命周期;二则是会话Bean的子类型。
-----------------------------------生 命 周 期-----------------------------------
先由一个例子引入:如果客户端代码调用用于完成“登录登记”的会话Bean,则EJB容器需要完成会话Bean组件实例的创建。在后续操作中,如果客户不再与该实例交互,应用服务器有可能会销毁它。也就是说:会话Bean实例开始于客户获得其引用时,而终止于客户会话的终结。映射到会话Bean的生命周期,可以说:客户会话(Client Session)的持续期就决定了使用中的会话Bean的存活期,也就是生命周期。而一般情况下,客户会话的持续期是比较短的,所以会话Bean的实例也是存活短暂的对象。
知道了会话Bean的生命周期后,那么操作会话Bean生命周期的又是什么呢?答案就是EJB容器。不仅仅是会话Bean,EJB容器管理着EJB全部组件的生命周期。例如客户超时,EJB容器将会销毁会话Bean实例。
-----------------------------------子 类 型--------------------------------------
会话Bean存在两种子类型:无状态会话Bean和有状态会话Bean,用于建模不同类型的会话。
一、无状态会话Bean
无状态会话Bean适用于只需单个请求会话即可完成的业务过程。这样,EJB组件不需要维护方法调用间的状态变更信息。
为了实现有效的Bean实例处理,EJB容器经常会使用实例池技术。下图是无状态会话Bean的实例池。我们可以清晰的导出无状态会话Bean的内部机制。
图1.1
由于无状态会话Bean不含会话状态,因此同一无状态会话Bean类的所有实例对于客户而言都是等效的。而且无状态会话Bean不保留历史会话信息,所以它对于调用其本身的客户也并不关注。因此,任何无状态会话Bean都能够服务任何客户请求。因为这些无状态会话Bean都是一样的。
了解了原理之后,来一个很简单的小Demo来加深对无状态会话Bean的理解吧。首先是EJB的服务器端:
/** * @ClassName: 无状态会话Bean Demo接口类 *@Description: EJB服务器端接口类 *@author 孙丽端 * @date 2014年11月28日20:22:51 */ package com.tgb.ejb; public interfaceStatelessEjb { publicvoid compute(int i); publicint getResult(); }
/** * @ClassName: 无状态会话Bean Demo实现类 *@Description: EJB服务器端实现类 *@author 孙丽端 * @date 2014年11月28日20:22:51 */ package com.tgb.ejb; importjavax.ejb.Remote; importjavax.ejb.Stateless; @Stateless @Remote public classStatelessEjbBean implements StatelessEjb { privateint state; @Override publicvoid compute(int i) { state= state +i; } @Override publicint getResult() { //TODO Auto-generated method stub return state; }
其次来看看EJB的客户端调用代码实现,客户端调用的是服务器端接口类的方法:
/** * @ClassName: 无状态会话Bean Demo客户端类 *@Description: EJB客户端类 *@author 孙丽端 * @date 2014年11月28日20:22:51 */ package com.tgb.ejb; importjavax.naming.InitialContext; importjavax.naming.NamingException; public classStatelessEjbClient { publicstatic void main(String[] args) throws NamingException { InitialContextcontext = new InitialContext(); StatelessEjbejb1 =(StatelessEjb)context.lookup("StatelessEjbBean/remote"); System.out.print(ejb1.getResult()); ejb1.compute(1); System.out.print(ejb1.getResult()); ejb1.compute(1); System.out.print(ejb1.getResult()); StatelessEjbejb2 =(StatelessEjb)context.lookup("StatelessEjbBean/remote"); System.out.print(ejb2.getResult()); ejb2.compute(1); System.out.print(ejb2.getResult()); ejb2.compute(1); System.out.print(ejb2.getResult()); } }
最后的运行结果是:
二、有状态会话Bean
有状态会话Bean适用于需要若干请求形成才可完成的业务过程。这样,EJB组件就需要维护方法调用间的状态变更信息,最形象的就是淘宝购物车的状态了。在用户浏览商品到加入购物车直至购买,我们必须跟踪用户的状态,并且为单个客户保存状态信息。
图1.1是无状态会话Bean的实例池,EJB容器只需要在实例池中维护若干个Bean实例,便能服务大量的并发的客户。可是对于有状态会话Bean来说,这样是远远不够的。
在有状态会话Bean中各个Bean实例中存储的状态信息仅是单个客户的。如果和无状态会话Bean的处理一样,只是简单的将实例全部放置实例池中,当大量的并发客户操作时,内存中运行的有状态会话Bean实例就会过多而失去控制。
因此,为了限制内存中Bean实例的数量,EJB容器使用了挂起和激活两个操作。咱们先来说说挂起吧。
挂起是什么呢?就和束之高阁一样的,把它先保存起来,以后再用。在这里就是当有状态会话Bean实例暂时没有参与到客户请求中时,容器就有可能挂起它,它的会话状态会被安全的保存下来,而且其释放的内存可以供其他应用(EJB实例)使用。具体的挂起原理如下图所示:
图 2.1
这时候读者朋友可能会问,那么EJB容器怎么知道该挂起那个Bean实例呢?上图中有提到,大部分容器使用最近最少使用的挂起策略,即简单的挂起最近没有使用到的有状态会话Bean实例。
一旦被挂起的有状态会话Bean实例的客户再次调用它,被挂起的会话状态将重新回到有状态会话Bean实例中。注意我说的是“被挂起的会话状态”,激活的有状态会话Bean实例不一定是原来使用的那个有状态会话Bean实例,也有可能是一个新的有状态会话Bean实例,可是这个新的有状态会话Bean实例获得的会话状态正是被挂起的有状态会话Bean实例的会话状态。所以我上句话说的是“被挂起的会话状态”,读者朋友需要格外注意这点。
具体的激活原理如下图所示:
图 2.2
同无状态会话Bean一样,我们最后也附上一个有状态会话Bean的小Demo供大家理解。
首先是EJB的服务器端:
/** * @ClassName: 有状态会话Bean Demo实现类 *@Description: EJB服务器端实现类 *@author 孙丽端 * @date 2014年11月28日20:22:51 */ package com.tgb.ejb; public interfaceStatefulEjb { publicvoid compute(int i); publicint getResult(); }
/** * @ClassName: 有状态会话Bean Demo实现类 *@Description: EJB服务器端实现类 *@author 孙丽端 * @date 2014年11月28日20:22:51 */ package com.tgb.ejb; importjavax.ejb.Remote; importjavax.ejb.Stateful; @Stateful @Remote public classStatefulEjbBean implements StatefulEjb { privateint state; @Override publicvoid compute(int i) { state= state +i; } @Override publicint getResult() { //TODO Auto-generated method stub returnstate; } }
其次是EJB的客户端调用代码实现:
/** * @ClassName: 有状态会话Bean Demo客户端类 *@Description: EJB客户端类 *@author 孙丽端 * @date 2014年11月28日20:22:51 */ package com.tgb.ejb; importjavax.naming.InitialContext; importjavax.naming.NamingException; public classStatefulEjbClient { publicstatic void main(String[] args) throws NamingException { InitialContextcontext = new InitialContext(); StatefulEjbejb1 =(StatefulEjb)context.lookup("StatefulEjbBean/remote"); System.out.print(ejb1.getResult()); ejb1.compute(1); System.out.print(ejb1.getResult()); ejb1.compute(1); System.out.print(ejb1.getResult()); StatefulEjbejb2 =(StatefulEjb)context.lookup("StatefulEjbBean/remote"); System.out.print(ejb2.getResult()); ejb2.compute(1); System.out.print(ejb2.getResult()); ejb2.compute(1); System.out.print(ejb2.getResult()); } }
最后的运行结果是:
通过对会话Bean的生命周期和两个子类型(有状态会话Bean和无状态会话Bean)的详细解说,不知道你明白了一些吗?
EJB初级篇--EJB组件之会话Bean