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

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

 

 

(上接第 2 章的第 2 部分)

 

21.    依赖注入

EJB 需要使用其他 EJB 或资源的时候,必须通过 JNDI 查找或者注入注释来实现,而不能使用 new object 的方式,因为 EJB 实例的创建与销毁都是由容器进行管理的。

 

22.    ENC 注册项

1) EJB 容器有一个自己的内部注册表( internal registry ),称为 Enterprise Naming Context ENC )。容器在 ENC 中维护某些外部环境的应用,可以认为 ENC 是容器的私人地址簿。先往 ENC 中登记资源,然后再从 ENC 中获取资源的引用。

2) 要往 ENC 添加引用的注册项,可以通过:

l            ejb-jar.xml (用于 EJB 模块)

l            web.xml (用于 WEB 模块)

l            注入注释

3) 使用 ejb-jar.xml 添加注册项:

< enterprise-beans >

       < session >

           < ejb-name > InjectionTestBean </ ejb-name >

           < ejb-ref >

              < ejb-ref-name > ejb/HelloWorldBean1 </ ejb-ref-name >

              < ejb-ref-type > Session </ ejb-ref-type >

              < remote > cn.gengv.ejb3ex.HelloWorld </ remote >

              < ejb-link > HelloWorldBean </ ejb-link >

           </ ejb-ref >

           < ejb-local-ref >

              < ejb-ref-name > ejb/HelloWorldBeanL </ ejb-ref-name >

              < ejb-ref-type > Session </ ejb-ref-type >

              < local > cn.gengv.ejb3ex.HelloWorldLocal </ local >

              < ejb-link > HelloWorldBean </ ejb-link >

           </ ejb-local-ref >

       </ session >

       < session >

           < ejb-name > InjectionTestBean3 </ ejb-name >

           < ejb-ref >

              < ejb-ref-name > ejb/HelloWorldBean3 </ ejb-ref-name >

              < ejb-ref-type > Session </ ejb-ref-type >

              < remote > cn.gengv.ejb3ex.HelloWorld </ remote >

              < ejb-link > HelloWorldBean </ ejb-link >

           </ ejb-ref >

       </ session >

    </ enterprise-beans >

 

4) 使用 @EJB 注释添加注册项

@Stateless

@EJB (

           name = "ejb/HelloWorldBean2" ,

           beanName = "HelloWorldBean" ,

           beanInterface = HelloWorldLocal. class

)

public class InjectionTestBean2 implements InjectionTestLocal {

}

 

5) 对应关系:

单独使用 ejb-jar.xml @EJB 注释都可以在 ENC 中添加注册项。

l            @EJB name()  ==>  <ejb-ref-name>

l            @EJB beanName()  ==>  <ejb-link>

l            @EJB beanInstance()  ==>  <remote> <local>

 

23.    获取 ENC 中的资源引用

1) 两种途径: JNDI 查找 @EJB 注入

2) JNDI 查找:

l            使用 InitialContext lookup() 方法,根据注册项引用名称进行 JNDI 查找;

l            <ejb-ref-name> @EJB.name() ,注册的应用名称,都是相对于 java:comp/env 上下文的;例如:

HelloWorld hw = (HelloWorld)ctx.lookup("java:comp/env/ejb/HelloWorldBean1");

l            注意,在不同的 EJB 中调用 lookup java:comp/env 会被解析为不同的上下文环境。例如在 EJB1 中调用 lookup(“java:comp/env”) 获取的就是 EJB1 ENC ;在 EJB2 中调用 lookup(“java:comp/env”) 获取的就是 EJB2 ENC

3) @EJB 注入:

l            只要给成员变量或者 setter 方法上标注 @EJB 注释, EJB 容器就会在 Bean 实例被创建时,自动往 Bean ENC 中添加一个注册项,同时把 EJB 的引用直接注入成员变变量或 setter 方法中。

l            依赖注入只能用于本地命名服务中,因此不能注入远程服务器对象。

 

24.    @EJB 依赖注入

1) @EJB 的属性:

l              name() :表示被引用的 EJB JNDI ENC 注册项名称,该名称相对于 java:comp/env 上下文。

l              beanInterface() :指定使用的 Bean 接口。该属性通常用来区分所使用的 EJB 引用是远程还是本地的。如果 @EJB 用在 Bean 类级别,则必须指定该属性;如果用在成员变量或者 setter 方法上时,可以省略。(个人理解,如果用在类级别而不指定该属性,则 @EJB 没有任何依据,来指定何种接口,隐式添加到 ENC 注册项;而在成员变量或方法级别, @EJB 至少可以通过成员变量的类型或 setter 的参数类型,指定该接口类型,隐式添加到 ENC 注册项)

l              beanName() :指定被引用的 EJB 的名称,其值与 @Stateless.name() @Stateful.name() ejb-jar.xml <ejb-name> 元素的值相等。

l              mappedName() :表示 EJB 的全局 JNDI 名称,而全局 JNDI 名称与容器厂商有关,不利于移植,因此不推荐使用,

2) @EJB 注释工作时,会自动引发容器在 JNDI ENC 中为被注入的元素创建一个注册项。

l            注册项名称:由 @EJB.name() 指定,如果没有指定名称,则容器会根据被注入的成员变量或 setter 方法的名称,设置 ENC 名。默认的 ENC 名称由被注入的类的全限定名和成员变量或方法的基础名组成。例如:

cn.gengv.ejb3ex.impl.InjectionTestBean/hw

l            注册项引用接口:由 @EJB.beanInterface() 指定,如果没有指定,容器会根据被注入成员变量类型或 setter 方法的参数类型来设定。

l            注册项引用的 EJB 名称:由 @EJB.beanName() 指定。

l            综上情况,使用 @EJB 注入而自动产生的注册项应该与如下 xml 设置的效果相同:

< enterprise-beans >

< session >

< ejb-name > InjectionTestBean </ ejb-name >

< ejb-ref >

< ejb-ref-name >

cn.gengv.ejb3ex.impl.InjectionTestBean/hw

</ ejb-ref-name >

< ejb-ref-type > Session </ ejb-ref-type >

< remote >

cn.gengv.ejb3ex.HelloWorld

</ remote >

< ejb-link > HelloWorldBean </ ejb-link >

</ ejb-ref >

</ session >

</ enterprise-beans >

 

25.    @EJB 注释属性的应用场合

1) 不带任何属性

当接口在 EJB-JAR 内只被一个 Bean 类使用的时候,可以这样引用。

对于 @EJB HelloWorldLocal hw;

l            唯一标识符就是 HelloWorldLocal 接口,应用服务器首先在注入方的 EJB-JAR 中查找使用 HelloWorldLocal 作为本地或远程接口的 EJB 类。如果有多个 EJB 类使用了该接口,则容器会抛出一个部署异常。

l            如果 EJB-JAR 作为 EAR 的一个模块被部署,则容器也会在其他 EJB-JAR 中查找使用了该接口作为本地或远程接口的 EJB 类。同样,如果多于一个,也会引发异常。

l            如果容器没能在 EAR 中找到该 EJB 引用,则它会继续在其他全局 EJB-JAR 中继续寻找。

l            如果指定了 beanName() JBoss 会遵循相同的过程,但它使用的唯一标示符是 beanName() 的值;如果指定了 mappedName() ,则 JBoss 不会进行任何搜索,而是根据 mappedName 值,直接从全局 JNDI 中获取 EJB 引用。

 

2) beanName() 属性

l            当业务接口被多个 Bean 类使用时,则必须指定 beanName 。否则,在 @EJB 注入注释工作时,容器无法判断使用哪个 Bean 类名称作为注册项引用 EJB 名称。(相当于无法确定用哪个 Bean 名称作为 <ejb-link>

l            如果引用的 EJB 不在 InjectionBean 所在的 JAR 文件中,而在 .ear 的其他 JAR ,则可以使用下面形式进行引用:

@EJB(beanName=”zhenxi.jar#HelloBean”) LocalHello helloworld;

 

3) name() 属性

l            如果业务接口只被一个 Bean 类用作本地或者远程接口,则使用 @EJB(name=”ejb/HelloWorld”) HelloWorld hw @EJB HelloWorld hw 效果一样;不同的是,前者在 ENC 的名称是 java:comp/env/ejb/HelloWorld ;而后者为 cn.gengv.ejb3ex.impl.InjectionTestBean/hw

l            如果业务接口被多个 Bean 类使用,要想单单只是用 name() 属性,则必须在 ejb-jar.xml 中配置注册项(在 EJB3.0 中, xml 部署描述文件的优先级高于注释,可以使用 xml 覆盖注释的配置)。如果不想配置 xml ,那就得一并使用 beanName 属性。

 

【个人观点】

实际上, name() 属性与是否有多个 Bean 类使用同一个业务接口,没多大关系。真正关系到是否一个业务接口被多个 Bean 类使用的,应该是 beanName() 属性。 要想使用注入,隐式地 ENC 添加注册项,不论用到或没用到 @EJB 的什么属性,真遇到一个业务接口被多个 Bean 类使用的时候,也照样还得 beanName() 出马来解决判断问题,否则容器不可能知道应该用哪个 Bean 类。

 

4) mappedName() 属性

l            容器会根据 mappedName() 的值,直接从全局 JNDI 中查找 EJB 引用,容器无需执行像 beanName() 属性那样的搜索规则。

l            mappedName() 属性值与厂商有关,可能会带来移植问题,应避免使用。

 

26.    补充要点

1) 可以将无状态会话 Bean 注入到有状态或无状态会话 Bean 中;也可以将有状态会话 Bean 注入到有状态会话 Bean 中;但不应该将有状态会话 Bean 注入到无状态会话 Bean 中。

2) 如果被注入的 jar 与使用者不在同一个 jar 中,例如使用者在 DependencyInjection.jar 中,而被注入的 EJB HelloWorld.jar JBoss 在启动时,会按默认发布顺序先发布 DependencyInjection.jar ,后发布 HelloWorld.jar 。然而,由于 DependencyInjection.jar 中用到了 HelloWorld.jar 中的 EJB ,所以会抛出找不到类的异常,导致 DependencyInjection.jar 发布失败。解决办法是:

修改 JBoss /server/default/conf/jboss-service.xml 文件,找到

<attribute name="URLComparator">

org.jboss.deployment.DeploymentSorter

</attribute>

 

<!--

<attribute name="URLComparator">org.jboss.deployment.scanner.PrefixDeploymentSorter

</attribute>

-->

修改成:

<!--

<attribute name="URLComparator">

org.jboss.deployment.DeploymentSorter

</attribute>

-->

 

<attribute name="URLComparator">org.jboss.deployment.scanner.PrefixDeploymentSorter

</attribute>

然后给 jar 文件编号,格式为 01_XXX.jar ,如 01_HelloWorld.jar 02_DependencyInjection.jar JBoss 会按照编号顺序发布 jar 文件。

 

27.    资源类型的注入

1) @javax.annotation.Resource 注释用来注入外部资源类型。其工作过程与 @EJB 相同,也是先往 JNDI ENC 添加一个指向资源引用的注册项,然后把资源引用注入到成员变量或者 setter 方法中。

2) @Resource 注释的属性

l            name() :用于指定外部资源的 JNDI ENC 名,该名称是相对于 java:comp/env 的。

l            type() :用于指定资源对应的 Java 类型。

l            mappedName() :指定资源的 JNDI 名,该值与厂商有关。

l            shareable() :指定资源是否共享,默认为 true

l            authenticationType() :指定有谁来负责权限验证,其值可以是 CONTAINER APPLICATION ,默认值为 CONTAINER ,即容器自动执行所需验证工作。如为 APPLICATION ,则 Bean 类需要在使用资源之前自行验证。

 

28.    注入与继承

1) 被注入到使用者中的 EJB ,可以被使用者的子类继承;

2) 在使用者的子类中,也可以通过重定义成员变量或者重写( override setter 方法来更改注入的资源。

3) 应当注意,注入的继承关系,是由类的继承关系产生出来的。

 

29.    自定义注入注释

可以通过自定义注入注释,并使用拦截器拦截生命周期事件的回调方法(例如 @PostConstruct ),利用 Java 反射机制,来实现注入。

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值