EJB3.0入门经典(笔记) - 第2章 EJB知识与运行环境设置(1)

2 EJB 知识与运行环境设置( 1

 

 

1.        会话 Bean 分为两种:无状态( Stateless )和有状态( Stateful )。

 

2.        会话 Bean 的实现需要:

1) 远程接口( Remote Interface

2) 本及接口( Local Interface

3) 实现类( Bean Class

 

3.        无状态会话 Bean

1) 实例池( Instance Pooling )技术

当无状态会话 Bean 被部署在应用服务器上的时候, EJB 容器会预先创建好该 Bean 的一些实例并放入对象池中。就像使用数据库连接池那样,当收到对 EJB 方法的访问请求时, EJB 容器会提取出一个实例为之服务,服务完毕后,再放回对象池中。

2) 由于无状态会话 Bean 更具性能优势,因此条件允许的情况下,应优先考虑使用无状态会话 Bean

 

4.        开发实现了远程接口的无状态 Bean

1) 首先,定义一个普通的接口,该接口应该包含业务逻辑方法。 EJB 客户端会使用这个接口类型的引用,去引用从 EJB 容器返回的存根( Stub )。

2) 其次,编写实现类

l            用到两个注释 @Stateless @Remote

l            @Stateless 的属性

name() :定义 EJB 的名称。在每个 EJB JAR 中,该名称必须是唯一的;但在 EAR 中,是可以重复的,因为 EAR 可以包含多个 EJB JAR ,而每个 JAR 可以有一个同名称的 EJB

mappedName() :指定 Bean 的全局 JNDI 名称,这个属性在 WebLogic Sun Application Server Glassfish 上有效。

l            @Remote

为无状态会话 Bean 指定远程接口,接受 .class 类型的属性;

每个 Bean 可以有多个远程接口,每个接口可以用逗号分开,如 :

@Remote({Hello.class, HelloWorld.class, World.class})

 

5.        打包导出 JAR 文件

1) Eclipse 打包向导

2) Ant 打包任务

通过 build.xml 配置打包任务:

 

<?xml version="1.0" encoding="UTF-8"?>

 

<project name= "HelloWorld" basedir= "." >

    <property environment= "env" />

    <property name= "src.dir" value= "${basedir}/src" />

    <property name= "jboss.home" value= "${env.JBOSS_HOME}" />

    <property name= "jboss.server.config" value= "default" ></property>

    <property name= "build.dir" value= "${basedir}/build" />

    <property name= "build.classes.dir" value= "${build.dir}/classes" />

 

    <path id= "build.classpath" >

       <fileset dir= "${jboss.home}/client" >

           <include name= "*.jar" />

       </fileset>

       <pathelement location= "${build.classes.dir}" />

    </path>

 

    <target name= "prepare" >

       <delete dir= "${build.dir}" >

       </delete>

       <mkdir dir= "${build.dir}" />

    </target>

 

    <target name= "compile" depends= "prepare" description= " 编译 " >

       <javac srcdir= "${src.dir}" destdir= "${build.dir}" >

           <classpath refid= "build.classpath" >

           </classpath>

       </javac>

    </target>

 

    <target name= "ejbjar" depends= "compile" description= " 打包 " >

       <jar jarfile= "${basedir}/${ant.project.name}.jar" >

           <fileset dir= "${build.dir}" >

              <include name= "**/*.class" />

           </fileset>

       </jar>

    </target>

 

    <target name= "depoly" depends= "ejbjar" description= " 部署 " >

       <copy file= "${basedir}/${ant.project.name}.jar" todir= "${jboss.home}/server/${jboss.server.config}/deploy" >

       </copy>

    </target>

 

    <target name= "undeploy" description= " 卸载 " >

       <delete file= "${jboss.home}/server/${jboss.server.config}/deploy/${ant.project.name}.jar" ></delete>

    </target>

</project>

 

 

3) 可以使用 http://localhost:8080/jmx-console 选择 service=JNDIView 来查看是否部署成功。

 

6.        EJB 命名,如果没有为 EJB 指定全局名称, JBoss 会在部署的时候根据默认规则为其命名:

1) 打包在 EAR 中:

本地接口: EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local

远程接口: EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote

2) 打包在 JAR 中:

本地接口: EJB-CLASS-NAME/local

远程接口: EJB-CLASS-NAME/remote

 

应当注意: EJB-CLASS-NAME 不包括包名。

 

7.        JNDI 调用

1) 配置 JNDI 信息

l            JNDI 驱动类名:

java.naming.factory.initial Context.INITIAL_CONTEXT_FACTORY ,用于指定 InitialContext 工厂,类似于 JDBC 的数据库驱动类。 JBoss 提供的驱动类是 org.jnp.interfaces.NamingContextFactory

 

l            命名服务提供者 URL

java.naming.provider.url Context.PROVIDER_URL ,用于指定提供命名服务的主机地址和端口号,类似于 JDBC 的数据库 URL JBoss 提供的 URL 格式为 jnp://host:port 。除主机名以外,其他部分都可以不写。

 

l            java.naming.security.principal java.naming.security.credential 用于指定用户标识(如用户名)和凭证(如密码)。当 EJB 提供安全服务时,必须提供这两个属性。即类似于 JDBC 连接数据库时的用到的用户名和密码。

 

2) 创建 InitialContext

如果客户端也运行在应用服务器内,则不需要为 InitialContext 设置上下文信息。应为应用服务器会把 JNDI 驱动类等上下文信息添加进系统属性,当使用 InitialContext 的无参数构造方法创建 InitialContext 时, InitialContext 内部会调用 System.getProperty() 方法从系统属性中获取必要的上下文信息。

 

3) 查找 EJB

使用 InitialContext lookup 方法,根据 EJB JNDI 名称,可以从 EJB 容器查找并返回回来一个存根对象。该存根对象实现了 EJB 的远程接口,它会将客户端的方法调用路由到应用服务器,应用服务器再将调用请求路由到真正的 EJB 实例上。

 

8.        开发实现了本地接口的无状态 Bean

1) 基本流程与远程接口相似

2) @Local @Remote 用法也基本相同

3) @Remote @Local 都不存在时,容器会将 Bean Class 实现的接口,默认认为本地接口。

 

9.        开发实现了远程和本地接口的无状态 Bean

1) 实际应用中建议将 Bean 类同时实现 Remote Local 接口。

2) 值得注意的是,实现了 Remote Local 接口的 Bean Class 可以为远程访问和本地访问提供服务。由于无状态会话 Bean 不会跟踪维护会话的状态,因此即使会话已经失效了, Bean 实例可能仍然存活于对象池中。而 Bean 实例自身的属性变量并未变化。所以,对接下来的调用,不论远程访问还是本地访问,都存在交叉影响的可能,需要做好处理。

 

10.    实例池( Instance Pooling

1) 主要用于无状态会话 Bean 和消息驱动 Bean ,而不能用于有状态会话 Bean

2) 实现很类似于 JDBC 连接池。

 

11.    无状态会话 Bean 的生命周期

1) 两种状态: does not exist method-ready pool

2) 进入 method-ready pool 状态,会完成三步操作:

l            容器会调用无状态会话 Bean 实现类的 Class.newInstance() 方法,构造一个 Bean 实例。因此必须提供无参的 public 构造方法。

l            根据注释或 .xml 部署描述文件,将在 Bean 元数据中声明的资源注入进来。

l            EJB 产生一个 post-construction 事件,该事件注册了一个回调方法,用来调用 Bean 类中标注了 @javax.annotation.PostConstruct 注释的方法。这种回调方法可以使用任何名称,但有如下限制: void 、无参数、不抛检查异常;每个 Bean 类只能有一个 @PostConstruct 回调方法,且实例的整个生命周期中只在此时调用一次。通常用来做初始化工作,比如打开资源等。

3) 处于 method-ready pool 状态

l            无状态会话 Bean 实例只在单个方法调用期间才与 EJB Object 关联。如果某个 Bean 实例正在处理请求,那么直到完成了这次处理,才可以被其他 EJB Object 关联使用。(作者没有仔细说明 EJB Object 是什么,以及和 Bean 实例的关系,但我猜可能就是后面所说到的骨架类( Skeleton )。在没有明确答案之前,姑且先这么认为)。

l            客户端通过注入或者 JNDI 查找 EJB 并获得应用,但引用的返回并不会导致无状态会话 Bean 实例的创建或者从池中被取出。直到 Bean 的方法被调用时,这些操作才会发生。

4) 离开 method-ready pool 状态

l            Bean 实例被删除,即回到 does not exist 状态。

l            EJB 产生一个 pre-destroy 事件,该事件注册了一个回调方法,用来调用 Bean 类中标注了 @javax.annotation.PreDestroy 注释的方法。该类型的回调方法与 @PostConstruct 类似,相似的限制。每个 Bean 类只能指定一个 @PreDestroy 方法,也只在生命周期的此时被调用一次。通常用来做清理工作,比如关闭打开的资源等。

 

12.    有状态会话 Bean Stateful Session Bean

1) 每一次 lookup() 调用都会创建一个新的 Bean 实例与之对应。

2) 如果想一直使用某一 Bean 实例,可以在客户端使用 Session 或者其他方式来缓存这个存根。

3) 用状态会话 Bean 必须实现 Serializable 接口。

 

13.    激活机制( Activation Mechanism

l            钝化( Passivation

当某一 Bean 实例很少被调用或者 EJB 容器需要减小系统开销的时候,容器会从内存中回收 Bean 实例,并连同其保存的会话状态,一起序列化到硬盘中,释放其占用的内存。

l            激活( Activation

直到客户端再次发出请求, EJB 容器才会根据所关联的 EJB 对象重新恢复 Bean 实例的状态。容器会重新创建一个新的 Bean 实例,并将钝化期间保存的内容逐一设置数据成员。 EJB 对象像钝化之前一样,将方法调用委托给这个 Bean 实例。

 

14.    有状态会话 Bean 的生命周期

1) 三种状态: does not exist method-ready passivated

2) 进入 method-ready 状态,只有当客户端第一次调用有状态会话 Bean 方法的时候,才会发生。完成三个步骤:

l            容器会调用有状态会话 Bean Class.newInstance() 方法,创建 Bean 实例。因此需要提供无参数的 public 构造方法。

l            完成引来注入。

l            调用 Bean 类中定义的 @PostConstruct 回调方法。

3) 处于 method-ready 状态

在此状态下, Bean 实例可以保持 Session 状态以及打开着的外部资源,为请求服务。

4) 离开 method-ready 状态

l            离开 method-ready 状态, Bean 实例不是进入 does not exist 状态,就是进入 passivated 状态,即不是被删除就是被钝化。

l            如果客户端调用了具有 @Remove 注释的 Bean 方法,则调用完成后, Bean 实例会被立即清除,进入 does not exist 状态。

l            如果 Bean 实例超时了,则容器会将 Bean 实例从 method-ready 转移到 does not exist 状态;此时,容器是否会调用 @PreDestroy 回调方法,完全取决于容器的具体实现。

l            如果 Bean 实例所处的事务还处在处理期间, Bean 是不能超时的。

5) passivated 状态

l            当进入 passivated 状态时, @PrePassivate 回调方法会被调用。

l            如果在此状态下超时,容器也会将 Bean 实例直接从 passivated 状态转移为 does not exist 状态,同时 @PreDestroy 回调方法也不会被调用。

6) 系统异常

l            无论何时,只要 Bean 方法抛出系统异常,容器就会将相关 EJB Object 置为无效,并销毁 Bean 实例。 Bean 实例会直接变为 does not exist @PreDestroy 也不会被调用。

l            系统异常包括:运行时异常及其子类、 java.rmi.RemoteException 及其子类在内的,任何未标注 @ApplicationException 注释的非检查异常。 EJB Exception 是一个运行时异常,因此也会被当作系统异常。

 

15.    EJB 的调用机制

1) EJB 部署到应用服务器上的时候, EJB 容器为 EJB 生成存根类( Stub )和骨架类( Skeleton )。存根类和骨架类对开发者来说,是不可见的。

2) 客户端使用 lookup() 方法在应用服务器的 JNDI 树中查找 EJB ,应用服务器将存根对象序列化后返回给客户端。此时客户端远程接口引用的是存根对象,接着开始业务方法的调用。

3) 业务方法调用过程:

l            客户端调用远程接口的业务方法,而实际上就是调用存根对象的业务方法(存根实现了远程接口);

l            方法调用经过 IIOP Runtime 被转换成 CORBA IIOP 消息发往应用服务器;

l            应用服务器接收到消息后,交由骨架类处理,骨架类解析 IIOP 协议消息,并调用 Bean 实例的业务方法;

l            骨架类将 Bean 实例业务方法的返回值,转换为 CORBA IIOP 消息发回客户端;

l            存根类解析收到的 CORBA IIOP 应答消息,将返回值传给客户端。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值