JNDI ENC与依赖注入

JNDI ENC与依赖注入
请搞清楚:通过注解还是XML注册资源,通过注入还查找得到资源,注解与XML等价方式。
以下说的是EJB引用资源

每个部署于应用服务器中的EJB容器都拥有一个属于它自己的内部注册表(internal registry),该内部注册表被称为Enterprise Naming Context(ENC),ENC是由JNDI实现的。开发人员可以通过注解或XML为某个EJB 的JNDI ENC(这是一个局部JNDI)定义资源、EJB或外部环境的别名,而后在编写EJB业务逻辑时,通过别名在JNDI中查找这些引用,在EJB3.0中,还可以把这些引用直接注入到bean数据成员中。

JNDI ENC中可以注册哪些内容
指向EJB接口的引用、JMS队列或主题的目标地址、JMS连接工厂、数据源、任何JCA资源、基本的数据类型常量,还有一些java EE服务(javax.ejb.TimerService、javax.transaction.UserTransaction、org.omg.CORBA.ORB)

如何配置JNDI ENC
ENC的JNDI名字空间可以通过XML或通过注解来定义。

如何从ENC中获取引用
通过InitialContext查找
@Stateful
@EJB(name=”ejb/ProcessPayment”, //类级的注解
beanInterface=ProcessPaymentLocal.class,
beanName=”ProcessPaymentBean”)
public class TravelAgentBean implements TravelAgentRemote{
public TicketDO bookPassage(CreditCarDO card,double amount){
ProcessPaymentLocal payment=null;
try{
//EJB厂商不同,初始化方式也许不同
javax.naming.InitialContext ctx=new InitialContext();
//如果是本地接口,对于其他资源(如EntityManagerFactory等)也是类似的查找方法
payment=(ProcessPaymentLocal)ctx.lookup(
“java:comp/env/ejb/ ProcessPayment”);//使用java:comp/env上下文
//如果是远程接口,要用narrow方法
Object ref= ctx.lookup(“java:comp/env/ejb/ ProcessPayment”);
(ProcessPaymentRemote)javax.rmi.PortableRemoteObject.narrow(ref,
ProcessPaymentRemote.class);
}catch(javax.naming.NamingException ne){…..}……..
}
}

使用EJBContext查找
javax.ejb.SessionContext和javax.ejb.MessageDrivenContext接口都继承自javax.ejb.EJBContext,并且都可以用来查找ENC注册项。
@Stateful
@EJB(name=”ejb/ProcessPayment”,
beanInterface=ProcessPaymentLocal.class,
beanName=”ProcessPaymentBean”)
public class TravelAgentBean implements TravelAgentRemote{
@Resource private javax.ejb.SessionContext ejbContext;
public TicketDO bookPassage(CreditCarDO card,double amount){
ProcessPaymentLocal payment=(ProcessPaymentLocal)ejbContext.lookup(
“ejb/ ProcessPayment”);
……….
}
}

注解注入
import com.titan.travelagent;//包名
@Stateful
public class TravelAgentBean implements TravelAgentRemote{
@EJB private ProcessPaymentLocal payment;//通过成员变量注解直接注入
//默认ENC名称为:com.titan.travelagent.TravelAgentBean/payment;
//或者通过setter方法注解直接注入
@EJB public void setProcessPayment(ProcessPaymentLocal payment){
//默认ENC名称为:com.titan.travelagent.TravelAgentBean/processPayment;
this.payment=payment;
}
}

XML注入
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<ejb-local-ref>
<ejb-ref-name> com.titan.travelagent.TravelAgentBean/payment </ejb-ref-name>注册名
<ejb-ref-type>Session</ejb-ref-type>EJB类型有Session、Entity
<local>com.tian.Processpayment.ProcessPaymentLocal</local>
实现接口的EJB,由于ENC名与注解的一致,这个配置会覆盖注解
<ejb-link>ProcessPaymentBean</ejb-link>
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
下面的payment也可以使用processPayment,以通过setter注入
<injection-target-name>payment</injection-target-name>
</injection-target>
</ejb-local-ref>
</session>
</enterprise-beans>

XML覆盖
XML可以覆盖注解,它比注解具有一更高的优先级。覆盖方式见上一节,通过XML可以覆盖注解中要引入的实现类。

注入与继承
如果父类的数据成员或成员方法标有注入用注解,则注入父类的引用也会在子类中被引入,子类也可以覆盖父类的注入注解,但是如果父类的方法是private的,那么子类是无法覆盖它的注入注解的,这时父类和子类可能存在两个不同的引用。

不同类型的引用与注入
EJB类型的引用
@java.ejb.EJB用于引入一个EJB,@java.ejb.EJBs用于引入多个EJB
@EJB(name=”ejb/ProcessPayment”, //ENC注册名
beanInterface=ProcessPaymentLocal.class,//接口
beanName=”processPaymentEJB”,//实现这个接口的类,如果有多个类实现这个接口,必须指定这个
mappedName=”….”)//根据EJB容器厂商的不同而有所不同,可能是一个键值,指向厂商的全局注册表
以上注解标注在bean class类之上,表示注册一个引用,要通过lookup查找,如果用于bean class的setter方法或数据成员(类型是EJB的成员),却表示直接注入

通过XML指定远程EJB引用
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>//EJB名
<ejb-ref>
<ejb-ref-name> com.titan.travelagent.TravelAgentBean/payment </ejb-ref-name>注册名
<ejb-ref-type>Session</ejb-ref-type> EJB类型有Session、Entity
<remote>com.tian.Processpayment.ProcessPaymentRemote</ remote> 远程接口
<ejb-link>ProcessPaymentBean</ejb-link>实现接口的EJB,如果接口有多个实现类必须配置
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>payment</injection-target-name>也可以使用processPayment
</injection-target>
</ejb-local-ref>
</session>
</enterprise-beans>

通过XML指定本地EJB引用
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<ejb-local-ref>
<ejb-ref-name> com.titan.travelagent.TravelAgentBean/payment</ejb-ref-name>注册名
<ejb-ref-type>Session</ejb-ref-type> EJB类型有Session、Entity
<local>com.tian.Processpayment.ProcessPaymentLocal</local> 本地接口
<ejb-link>ProcessPaymentBean</ejb-link> 与注解beanName等价,表示引用的EJB名。
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>payment</injection-target-name>也可以使用processPayment
</injection-target>
</ejb-local-ref>
</session>
</enterprise-beans>

EJB名称的二义性和重载
对于某个特定的EJB JAR部署包而言,部署描述文件中的<ejb-name>元素及任何@Stateless或@Stateful注解的name属性必须是全局唯一的。但是对于同一个.ear文件的不同EJB-JAR部署包内,EJB名称是可以重复的,这了区分这些EJB,可以使用扩展语法:@EJB(beanName=”inventory-ejb.jar#InventoryEJB”) InventoryLocal inventory;

EntityManagerFactory类型的引用
在应用服务器对ENC进行配置或将EntityManagerFactory注入到EJB中之后,应用服务器会为你管理EntityManagerFactory实例的生命周期。定义引用的方式:
@javax.persistence.PersistenceUnit(name=”persistence/TitanDB”,//JNDI ENC名
unitName=”TitanDB”)//persistence.xml文件中声明的persistence unit名称
该注解标注bean class时,表示不直接注入,如果标注在bean class的setter方法或数据成员上,表示直接注入,如:
@ PersistenceUnit(unitName=”crmDB”)private EntityManagerFactory crm;
如果要引用多个persistenceunit,要使用@PersistenceUnits注解。

通过XML指定EntityManagerFactory类型的引用
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<persistence-unit-ref>
< persistence-unit-ref-name>persistence/TitanDB</persistence-unit-ref-name>注册名
persistence.xml文件声明的persistence unit名
< persistence-unit-ame>TitanDB</ persistence-unit-ame>
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>ships<injection-target-name>
</injection-target>
</ persistence-unit-ref >
</session>
</enterprise-beans>

Persistence Unit名称的作用域及重载问题
可以在不同的地方声明persistence unit,它可以定义在EJB-JAR、EAR/lib目录下的JAR或WAR文件中。如果定义的persistence unit有重名,可以通过这个扩展语法访问:@ PersistenceUnit(unitName=”inventory.jar#InventoryDB”)

EntityManager类型的引用
当将EntityManager注册到JNDI ENC或注入到EJB时,EJB容器会对EntityManager所依赖的persistence contect具有完全的控制权(控制它的生命周期),注册方式与EntityManagerFactory很相似,如:
@PersistenceContext(name”persistence/TitanDB”//JNDI ENC名
unitName=”TitanDB”//与peristence.xml文件中声明的peristence unit名称相同
type=PersistenceContextType.EXTENDED)//表示extended persistence context(方法间事务,只用于 //stateful session),还有一个取值TRANSACTION。
可以用于标注bean class,当标注在bean class的setter方法或数据成员上时,表示直接注入,如:
@ PersistenceContext(unitName=”crmDB”)private EntityManager crm;

通过XML指定EntityManager类型的引用
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<persistence-context-ref>
<persistence-context-ref-name>persistence/TitanDB</persistence-context-ref-name>名
persistence.xml文件声明的persistence unit名
<persistence-context-ame>TitanDB </persistence-context-ame>
<persistence-context-type>EXTENDED</persistence-context-type>
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>ships<injection-target-name>
</injection-target>
</ persistence- context -ref >
</session>
</enterprise-beans>

资源类型的引用
外部资源同样会被映射到JNDI ENC名字空间中的名称上,并且可以有选择地注入到bean实例的数据成员或setter方法中,被引用的外部资源类型可以是:javax.sql.DataSource、javax.jms.ConnectionFactory、javax.jms.QueueConnectionFactory、javax.jms.TopicConnectonFactory、javax.mail.Session、java.net.URL、javax.resource.cci.ConnectionFactory以及由JCA资源适配器定义的其他类型。下面以javax.sql.DataSource为例。

@javax.annotation.Resource(annotation:注解)
@ Resource注解除了用来引用外部资源,还可以用来引用JMS消息的目标地址、JNDI的环境注册项、EJBContext,以及其他Java EE的核心服务。

@ Resource(name=”jdbc/OracleDB”,//JNDI ENC名
type=javax.sql.DataSource,//引入的类别
authenticationType=AuthenticationType.APPLICATION,
//认证方式,有容器认证(取值CONTAINER,容器根据部署的用户名和密码进行认证)和程序自行认证
//(getConnection时要提供用户名和密码)
shareable=true,//多个EJB在同一事务中是否可以使用相同的资源,使用相同的资源连接,以提高性能
mappedName=”java:/DefaultDS”)//外部资源的厂商专用标识符,大多数情况,它的取值等价于一个 //全局JNDI名。
如果要引用多个资源,可以使用@javax.annotation.Resources注解

通过XML指定资源类型的引用
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<resource-ref>
<res-ref-name>jdbc/OracleDB</res-ref-name>ENC注册名
<res-type>javax.sql.DataSource</res-type>类名
<res-auth>Container</res-auth>
<mapped-name>java:/DefaultDS</mapped-name>
java:/DefaultDS是一个全局JNDI中定义的一个数据源,数据源的配置请查询相关书籍

<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>oracle<injection-target-name>
</injection-target>
</resource-ref >
</session>
</enterprise-beans>

资源环境和受管对象
资源环境注册项可以引用包含受管对象的资源,受管对象是一种在部署期间被配置到容器中,并在运行期间由容器负责管理的资源,它的配置书中没有给出例子。资源环境注册项也可可以用于诸如:javax.transaction.Usertransaction和javax.transaction.TransactionSynchronizationRegistry服务,这时定义authenticationType和shareable 是非法的。
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<resource-env-ref>
<resource-env-ref-name>jdbc/OracleDB</resource-env-ref-name>//ENC注册名
<resource-env-ref-type>javax.transaction.Usertransaction</resource-env-ref-type>类
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>utx<injection-target-name>
</injection-target>
</resource-env-ref >
</session>
</enterprise-beans>

环境注册项还可以用来配置String、Integer、Long、Double、Float、Byte、Boolean和Short这些包装类型的常量。
<enterprise-beans>
<session>
<ejb-name>ProcessPaymentBean</ejb-name>
<env-entry>
<env-entry-name>minCheckNumber</env-entry-name>ENC注册名
<env-entry-type>java.lang.Integer</env-entry-type>类名
<env-entry-value>2000</env-entry-value>常量值,这种引用几乎都是用XML来配置的
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.processpayment.ProcessPaymentBean
</injection-target-class>
<injection-target-name>minCheckNumber<injection-target-name>
</injection-target>
</env-entry>
</session>
</enterprise-beans>

消息目标地址类型的引用
在JNDI ENC中注册的消息目标地址引用指向JMS的主题或队列。
@Resource(name=”jms/TicketTopic”,//ENC名
type=javax.jms.Topic,//类型,还可以是队列(javax.jms.Queue)
mappedName=”topic/TicketTopic”)//全局的厂商专用标识符
注意,使用注解无法设置目标地址的连接(message-destincton-link)
等价XML
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<message-destination-ref>
<message-destination-ref-name>jms/TicketTopic</message-destination-ref-name>注册名
<message-destination-type>javax.jms.Topic</message-destination-type>消息类型
从目标地址收消息还是向其发消息
<message-destination-usage>Produces</message-destination-usage>
<message-destination-link>Distributor </message-destination-link>消息分发地址
<mapped-name> topic/TicketTopic </mapped-name>
topic/TicketTopic表示主题,它的配置请找相关书籍,原书练习中只讲到配置队列
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>ticketTopic <injection-target-name>
</injection-target>
</ message-destination-ref >
</session>
</enterprise-beans>

Web Service类型的引用
在JNDI ENC中注册的web service引用指向服务的接口或服务的终端接口。19章有详细介绍
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<service-ref>
<service-ref-name>service/ChargeItProcessorService</service-ref-name>ENC注册名
<service-interface>com.charge_it.ProcessorService</service-interface>JAX-RPC服务接口
<wsdl-file>META-INF/wsdl/ChargeItProcesor.wsdl</wsdl-file> WSDL文件位置
<jaxrpc-mapping-file>META-INF/mapping.xml </jaxrpc-mapping-file> JAX-RPC映射文件
<service-qname>chargeIt:ProcessorService</service-qname>与WSDL文件定义的服务名一致
<mapped-name>webservice/ChargeItProcessorService</mapped-name>
webservice/ChargeItProcessorService映射应用服务器全局注册项
<injection-target> 要直接注入时才用这个配置
<injection-target-class>
com.titan.travelagent.TravelAgentBean
</injection-target-class>
<injection-target-name>chargeService <injection-target-name>
</injection-target>
</ message-destination-ref >
</session>
</enterprise-beans>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值