EJB 知识与运行环境设置

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 反射机制,来实现注入。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gengv/archive/2009/07/17/4358264.aspx
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值