posts - 66,  comments - 11,  trackbacks - 0
    会话Bean同其他企业Bean类型最主要的区别是生命周期的差异性。会话Bean实例是存活短暂的对象,会话Bean实例并不能够在多客户间共享。
    通常,客户会话的持续期决定了使用中的会话Bean的存活期,一旦应用服务器瘫痪,会话Bean实例也应该不复存在。因为,会话Bean仅仅是内存对象,一旦其生存的周边环境遭到破坏,会话Bean也将不复存在。会话Bean并不是持久化的,因此,会话Bean并不会保存到持久化存储源中,这同实体Bean不一样,会话Bean能够操作RDBMS,但是其本身并不是持久化对象。
    会话指客户同EJB组件的交互,它由客户和EJB组件间的多次方法调用构成。会话Bean存在2种子类型:有状态会话Bean和无状态会话Bean,各自用于建模不同类型的会话。有状态会话Bean是这样一种EJB,即其服务的业务过程能够延伸到多个方法请求或者事务中,为完成这种业务过程,有状态会话Bean需要为单个客户保存状态信息。如果在方法调用期间有状态会话Bean的状态发生改变,则这种改变必须反映到同一客户的随后调用中。无状态会话Bean是这样一种EJB,即其服务的业务过程只需要单个业务方法即可完成。由于他们不需维护客户多个方法调用间的会话状态,因此它是无状态的。在每次方法调用结束后,EJB容器可能会销毁无状态会话Bean实例,或者实例化新的实例,或者清楚掉上次方法调用中的相关信息。
    无状态意指不存在会话状态。无状态会话Bean能够含有同特定客户不相关的状态信息,比如所有客户将使用到数据库链接工厂,开发者可以将它存储在private变量中。如果开发者将数据存储在private变量中,则将随时丢失其中存储的数据。
    EJB容器将维护EJB实例池,而且这些EJB实例是可重用的。在每次方法调用时,都会有不同EJB实例或同一实例服务客户。为了限制内存中运行的有状态会话Bean实例的数量,EJB容器需要将有状态会话Bean的会话状态保存到硬盘或者其他存储源中。该过程称之为挂起。在挂起有状态会话Bean后,会话状态被安全的保存下来,而且其释放的内存可以供其他应用使用。一旦被挂起的有状态会话Bean实例的客户再次调用它,被挂起的会话状态将重新回到有状态会话Bean实例中,该过程称之为激活。
    有状态会话Bean实例的会话状态必须遵循Java对象序列化设定的规则。在挂起有状态会话Bean实例时,EJB容器借助于对象序列化将会话状态转换成二进制blob,然后将它写入到硬盘中。在转移会话状态信息后,有状态会话Bean实例(指刮起了会话状态的那些EJB实例)还能够服务于其他客户,即同新的客户进行新的会话过程。

    一旦EJB中的成员变量符合如下条件,则可以认为它是会话状态的组成部分之一。
1、成员变量是非transient类型的java原始类型。
2、成员变量是非transient类型的Java对象类型。
    当容器将EJB实例挂起时,它需要将实例的会话状态写入到二级存储源中,比如文件或者RDBMS中。通过调用EJB实例的ejbPassivate()回调方法,容器能够完成实例的挂起工作。借助于ejbPassivate()方法能够告知EJB实例:EJB容器需要挂起它,这使得释放其持有的资源成为可能。比如EJB实例可能持有的资源有:RDBMS连接、已打开的Socket和文件或者其他任何资源。
    在实际场合中,客户调用了EJB对象中的某个方法,而当时在内存中暂时找不到该EJB对象,与此同时,EJB容器持有的企业Bean实例的个数已经到达了设定的上限。因此在处理客户请求前,容器需要挂起最近未使用的EJB实例,在挂起它后,容器才能够获得所需的EJB对象。
    有状态会话Bean的部署描述符。
   
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation
="http://java.sun.com/xml/ns/j2ee
 http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"
>
    
<enterprise-beans>
        
<session>
            
<ejb-name>Count</ejb-name>
            
<home>examples.CountHome</home>
            
<remote>examples.Count</remote>
            
<ejb-class>examples.CountBean</ejb-class>
            
<session-type>Stateful</session-type>
            
<transaction-type>Container</transaction-type>
        
</session>
    
</enterprise-beans>
</ejb-jar>

服务端企业Bean:
package com.wyq.ejb02;

import java.rmi.RemoteException;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
/**
 * 演示有状态Bean
 * 它会初始化val,并提供业务方法。
 * 该实例演示了最简单的有状态会话Bean,并给出了挂起、激活的工作机理。
 
*/
public class CountBean implements SessionBean {
    
//会话状态
    public int val;
    
//业务方法
    public int count(){
        System.out.println(
"count");
        
return ++val;
    }
    
public void ejbCreate(int val)throws CreateException{
        
this.val = val;
        System.out.println(
"ejbCreate()");
    }
    
public void ejbActivate() throws EJBException, RemoteException {
        System.out.println(
"ejbActivate()");
    }

    
public void ejbPassivate() throws EJBException, RemoteException {
        System.out.println(
"ejbPassivate()");
    }

    
public void ejbRemove() throws EJBException, RemoteException {
        System.out.println(
"ejbRemove()");
    }

    
public void setSessionContext(SessionContext ctx) throws EJBException,
            RemoteException {
    }

}
客户端调用:
package com.wyq.ejb02;

import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

import com.wyq.ejb01.HelloHome;
/**
 * 1、获得JNDI InitialContext上下文。
 * 2、借助于JNDI,定义Home对象。
 * 3、使用Home对象创建3个不同的CountEjb对象。因此,这将建立起3个不同的会话过程,而且模拟了3个不同的客户。
 * 4、由于内存中仅能存活2个EJB实例,因此在创建Count EJB实例期间,EJB容器需要完成实例的挂起操作。
 * 5、调用各个EJB对象的count()方法。
 * 6、最后,删除所有的EJB对象。
 
*/
public class CountClient {

    
/**
     * 客户代码示例
     * 
     * 此时,创建了3个EJB对象。但我们规定容器:在内存中最多存在2个实例。
     * 因为,能够看到挂起操作的发生。
     
*/
    
public static void main(String[] args) {
        
try{
            
/*
             * 获得JNDI环境属性
             
*/
            Properties props 
= System.getProperties();
            
/*
             * 获得对Home对象的引用,Home对象是EJB对象的工厂
             
*/
            Context ctx 
= new InitialContext(props);
            
            Object obj 
= ctx.lookup("CountHome");
            
            CountHome home 
=(CountHome)javax.rmi.PortableRemoteObject.narrow(obj,CountHome.class);
            
/*
             * 能够持有3个Count对象的数组 
             
*/
            Count count[] 
= new Count[3];
            
int countVal = 0;
            
/*
             * 创建EJB实例,并调用各自的count()
             
*/
            System.out.println(
"Instantiating beans");
            
for(int i=0;i<3;i++){
                
/*
                 * 创建EJB对象,并初始化它们
                 
*/
                count[i]  
= home.create(countVal);
                
/*
                 * 加1,并打印出来
                 
*/
                countVal 
= count[i].count();
                System.out.print(countVal);
                
/*
                 * 等待1/2秒
                 
*/
                Thread.sleep(
500);
            }
            
/*
             * 调用各个EJB对象的count()方法,从而能够浏览到EJB被挂起,并被成功激活
             
*/
            System.out.println(
"Calling count() on beans");
            
for(int i=0;i<3;i++){
                
/*
                 * 加1,并打印出来
                 
*/
                countVal 
= count[i].count();
                System.out.println(countVal);
                
/*
                 * 等待1/2秒
                 
*/
                Thread.sleep(
500);
            }
            
/*
             * 使用完后,销毁它们
             
*/
            
for(int i=0;i<3;i++){
                count[i].remove();
            }
        }
catch(Exception e){
            e.printStackTrace();
        }

    }

}

会话Bean的声明周期流程图
1、起初,EJB实例并不存在。
2、EJB容器将决定是否需要实例化新的EJB实例。容器将何时实例化新的EJB实例,取决于容器使用的EJB实例池策略。
3、容器实例化EJB Bean类。EJB容器将调用Class.newInsatance("HelloBean.class");即动态创建HelloBean实例,这使得容器不会将EJBBean类的名字硬编码在Java代码中。最后,这使得容器更具通用性,能够操控任何企业Bean.
4、容器调用setSessionContext()方法。这为EJB实例设置了上下文对象。最终,EJB实例将能够访问到EJB容器。
5、容器调用ejbCreate().这将初始化EJB实例。由于无状态会话Bean的ejbCreate()方法并不存在参数,因此EJB客户不可能为它提供任何启动EJB实例的参数信息。
6、EJB容器调用EJB实例的业务方法。对于EJB实例提供的所有业务方法,EJB容器都可以使用。由于所有EJB实例间不存在区别,因此完全不同的客户可以调用相同的业务方法。在业务方法调用结束后,各个无状态会话Bean实例依然是相同的,因此,EJB容器能够针对客户请求,在每个方法级将各个EJB实例指定给客户,即使同一客户对同一业务方法的多次调用,都可以由不同的EJB实例响应它,当然,将EJB实例指定给客户的具体实现策略取决于具体的EJB容器。
7、最后,容器调用ejbRemove()方法。

posted on 2009-11-02 16:35 王永庆 阅读(178) 评论(0)  编辑  收藏 所属分类: EJB学习笔记

只有注册用户登录后才能发表评论。


网站导航:
 
<2009年11月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

常用链接

留言簿(1)

随笔分类

随笔档案

关注blogs

搜索

  •  

最新评论

阅读排行榜

评论排行榜