站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2EE 专题在 Java EE 5.0 中使用依赖注入

在 Java EE 5.0 中使用依赖注入

摘要: 依赖注入又称控制反转(IOC)是当前最新的开发潮流。诸如Spring 等IOC容器变得流行,就是因为它简化了企业java的復杂性,这些復杂性大部份是来自於JNDI。在这篇文章中,我会讨论如何在即将发布的Java EE 5.0中使用依赖注入为资源和服务进行声明。我将使用EJB3.0,Web Servic的元数据和依赖注入移植J2EE1.4蓝图程序java高级编译器。在这篇文章中我将使用这个应用程序去说明这些概念。
依赖注入又称控制反转(IOC)是当前最新的开发潮流。诸如Spring 等IOC容器变得流行,就是因为它简化了企业java的復杂性,这些復杂性大部份是来自於JNDI。在这篇文章中,我会讨论如何在即将发布的Java EE 5.0中使用依赖注入为资源和服务进行声明。我将使用EJB3.0,Web Servic的元数据和依赖注入移植J2EE1.4蓝图程序java高级编译器。在这篇文章中我将使用这个应用程序去说明这些概念。

版权声明:任何获得Matrix授权的网站,转载时请务必保留以下作者信息和链接
作者:EsunYang(作者的blog:http://blog.matrix.org.cn/page/EsunYang)
原文:http://www.matrix.org.cn/resource/article/44/44321_Dependency+Injection.html
关键字:Dependency;Injection

什么是依赖注入?

大多数企业级java应用程序都使用了诸如DataSources,EJBs或WebService的外在的资源和服务,在J2EE 1.4中,用户必须在部署描述符中明确声明所依赖的资源或者使用JNDI的lookup方法去获得资源的引用。

例如,如果你想在J2EE 1.4 中使用诸如DataSource 或EJB这样的服务,你必须在部署描述符作出类似下面的定义:

ejb/HelloWorld
oracle.ejb30.HelloWorld


然后,在可以使用下列资源之前,你还必须像下面一样使用JNDI去查找这个对象:
Context ic = new InitialContext();
HelloWorld helloWorld = (
HelloWorld)ic.lookup("java:comp/env/ejb/HelloWorld");


这些方法不仅仅使java新手感到难以理解,而且容易误导。而这些都归功於J2EE的復杂性。
依赖注入与JNDI相反,它(依赖注入)让你声明依赖,当需要请求资源时,由java EE容器处理资源或服务的復杂实例化和初始化。基於使用註释或部署描述符的资源声明,在必要时,Java EE 5.0容器会插入一个资源实例。图1对JNDI和依赖注入作了比较:


图1. JNDI和依赖注入的比较

在何处使用依赖注入?

依赖注入仅可以由受管对象使用,受管对象是指由Java EE容器管理的对象,比如EJB或Servlet,而不是那些诸如助手类(helper class)的一切类。例如,如果我们有一个EJB,我们可以在EJB3.0使用依赖註入,而不是在它所依赖的助手类上使用依赖注入。下表列出了在web和EJB模块中支持依赖注入的类型:



一些Java EE容器,如Oracle Application Server 10g 10.1.3 和 JBoss Application Server 4.0,为EJB3.0提供较早的支持,因此在EJB容器中他们是支持依赖注入的。

正如我上面的描述一样,你既可以使用元数据註解或部署描术符去声明对资源的依赖。在最近提交的作为最后定稿的JSR250中,为java平臺的通用元数据註解定义了两个资源依赖注解类(javax.annotation.Resource 和 javax.annotation.Resources),在JSR200中的EJB3.0中,为EJBs的依赖註解定义了javax.ejb.EJB,而在Java API for XML web service 2.0中为Web Servcie引用的依赖註解定义了javax.xml.ws.WebServiceRef。

Resource 注解可以用於诸如EJB或 Servlet 等受管类,或者它们(受管类)中的方法和字段。你可以用Resource註解去定对任何类别资源的依赖,如DataSource,JMS,Mail,URL,或environment enries(环境条目)。
下面是一javax.annotation.Resource接口的註解声明:
public @interface Resource {    
public enum AuthenticationType {CONTAINER,APPLICATION
}
String name() default '';
Class type() default Object.class;
AuthenticationType authenticationType()
default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName default '';
description() default '';
}


下表描述了可以在javax.annotation.Resource中指定的参数:


註入类型
Java EE 5.0支持两种类型的註入:field和Setter。Field註入(字段註入)允许你向一字段註入资源,而setter註入(设定註入)允许你通过调用setter方法註入资源。

要使用field註入,只需定义一字段,然註解它所引用的资源。如果你没有定义所引用的资源名称和类型,容器将从字段的名称和类型中继承信息。例如,你可以像下面一样註解DataSource(数据资源):
@Resource 
private javax.sql.DataSource AdventureDB;


在上例中,应该配置一个带有AdventureDB JNDI名称的DatatSource﹔如果没有配置的话,将会拋出一个异常。在客户可访问一个受管对象之前,必须先完成对依赖的註入。

相反,setter 註入(或property 註入)让你按JavaBean规范定义一个set…()方法,并注解它为一个资源引用。应用程序不必去调用这个setter方法,容器会在调业务方法之前去调用这个用於註入资源的setter方法。例如,如果你有一个名为adventureDB字段,就必须有一名为setAdventureDB的setter方法。如查你没有定义setter所註入名称和类型,”註入”将从setter方法的名称我参数类型中继承信息。例如,下面有一个对资源进行引用的setter方法:
@Resource 
private void setAdventureDB(javax.sql.DataSource ds)
{
adventureDB = ds;
}
private DataSource adventureDB;


让我们来看一些在 Java EE应用程序中使用Resource 註解进行依赖註入的典型用法。

使用Resource 註解进行依赖註入

使用数据源
在java应用程序中数据源是经常被使用的。你可以使用依赖註入而不是使用JNDI去获得一个数据源。例如,在你的环境中有一个名为jdbc/AdventureDB的数据源,你可以像下面那样去获得对这个数据源的引用:
@Resource(name="jdbc/AdventureDB") 
private javax.jdbc.DataSource myDB;
Connection con;
con = myDb.getConnection();


使用JMS资源
Java消息服务(JMS)使得以消息为向导的中间件(MOM)非常容易被使用,并且在java EE应用程序中这两项技朮被大量地使用。你可以使用资源注解去插入一个如Queue(队列)或Topic(主题)的JMS目标,或如连接工厂的工厂资源。例如,如果你想使用一个JMS资源,你首先在服务器的配置上创建它,然后像下面那样使用一个@Resource的注解去声明一个依赖:
@Resource(name="jms/WorkFlowManagerQueue")
private Queue wfmQueue;


使用环境条目
环境条目可以让你指定一个因时间或环境不同而变化的业务参数。例如,假设你想在你的应用程序中设定一个用户每月可以交易的最大数量,如果你在应用程序中进行硬编码是没意义的,因为你想在以后可以改变它的数值,或者你想用不同的数值去测试你的產品系统。
比如你想设定maxTradesAllowedPerUser的值为50,你可以像下面那样声明:
@Resource int maxTradesAllowedPerUser = 50


然而仅仅使用注解去声明一个环境条目是没意义的,因为注解是应用代码的一部分。因此你应使用部署描述符去插入一个值。
 
maxTradesAllowedPerUser
java.lang.Integer
15

maxTradesAllowedPerUser



使用邮件资源
你可以使用Resouce注解去插入一个邮件会话的实例。首先,在应用服务器上你应配置一个邮件资源﹔然后你就可以使用Resource注解向你的应用程序插入一个邮件会话。
@Resource(name="mail/Adventure ") 
private javax.mail.Session ms;
EJB上下文(EJBContext)


你可以像下面那样,使用Resource注解去插入SessionContext和MessageDrivenContext:
@Resource javax.ejb.TimerService ts;


时间服务(TimeService)
TimeService使EJB组件可以访问容器的时间服务,并且允许在EJB应用中安排任务和活动计划。你可以像下面那样使用Resource注解向一个EJB插入时间服务:
@Resource javax.ejb.TimerService ts;


通过javax.annotation.Resource使用多种资源
如果你想在你的应用程序使用多种资源,请像下面那样使用javax.annotation.Resource:
@Resources ({     
@Resource(name="jdbc/AdventureDB" type=javax.sql.DataSource),
@Resource(name="jms/wfmQCF" type=javax.jms.QueueConnectionFactory)})



EJB中使用依赖注入

在J2EE 1.4中,EJB是非常復杂的,并且它还继承一些JNDI的繁杂性。在EJB3.0中,通过使用javax.ejb.EJB注解或ejb-ref部署描述符元素声明对另一个会话Bean的依赖是非常方便的。下面就是javax.ejb.EJB注解的声明:
@Target({TYPE, METHOD, FIELD}) 
@Retention(RUNTIME)
public @interface EJB {
String name() default "";
String beanName() default "";
String mappedName() default "";
String description() default "";
Class beanInterface() default Object.class;
}


下表列出javax.annotation.EJB的参数:


如果你想使用一个名为ProcessManager的EJB,你可以使用依赖解去获得ProcessManager的实例并调用它的方法:
@EJB(name="ProcessManager") 
private ProcessManager pm;
pm.submitOrder(order);


这里,name是一个被插入的JNDI名称。当一个EJB被用作类时,并且没有办法知道组件将使用那一个执接口时,必须指定interface。如果这个Bean与另一个Bean使用的相同的接口,那麼要用beanName去消除岐义。

通过依赖註入使用Web Service

在J2EE中开发和调用Web Services是非常復杂的。通过运用web services metadata(JSR-181)和Java API for XML web service 2.0(JSR-224),Java EE5.0简化了基於XML的web services的开发及调用。你可以使用javax.xml.ws.webServiceRef注解为web services声明依赖或註入。

下表列出可以在WebServiceRef注解中使用的参数。



下面是一个WebService注解的例子,它的类型取值和名称从被插入的对象中继承:
@WebServiceRef 
public PurchaseOrderService poService;


使用依赖註入的好处和限制

效果
依赖註入可以使得资源和服务更易被使用,因为你不必处理JNDI的復杂性。你不必去写几百行的代码或去写服务定位器模板。
Java EE既支持使用XML的依赖註入也支持注解的依赖註入,如果你觉得注解更有意思你可以使用注解。注解可以使你的代码更具可读性且更简练,但这并不意味著它使你生活更舒适,因为它会导至代码维护问题,这主要是因为方法所需求的引用资源是硬编码到应用程序中的。好的消息是你可以用XML元素去改写注解。

限制
因为Java EE 5.0只支持受管对象的依赖註入,所以你不可以在助手类中使用依赖注入,在助手类中如果你想使用资源或服务仍然必须使用JNDI。

总结
依赖註入大简化了JNDI的復杂性,使得开发企业应用程序更容易。你可以亲自试试注解如何使得使用资源和服务变得更容易:可以在Oracle的Application Server 10g 10.1.3和JBoss 4.0.x作练习,他们在EJB容器中都对EJB3.0和依赖註入提供较早的支持。

相关资源
Matrix Java社区:http://www.matrix.org.cn
OTN EJB 3.0 Resource Center
Java EE 5.0 Early Release draft specification (JSR 244)
Common Metadata annotations for Java Platform Proposed Final Draft specification (JSR 250)
EJB 3.0 Public Draft specification (JSR 220)
Java API for XML web services 2.0 Proposed Final Draft specification (JSR 224)
↑返回目录
前一篇: Hibernate+JDBC将Blob数据写入Oracle
后一篇: 在Spring中使用JDO