浅谈CDI——JavaEE平台的上下文与依赖注入

CDI中最令人兴奋的功能是允许每个人在Java EE平台中编写强大的扩展性功能,甚至于改变其核心本身。这些扩展性功能是可以完全移植到任何支持CDI的环境中。本文是对CDI提供的主要功能进行一个概述,并通过一个Web应用示例来介绍框架的运行机制。

目前有三种实现CDI的方式: JBoss Weld(参考实现)、 Caucho CanDI和Apache OpenWebBeans。已经有几个框架提供了CDI的扩展性功能,如:Apache DeltaSpike、 JBoss Seam 3、和 Apache MyFaces CODI。

一些历史
CDI规范的产生是为了填充后端的EJB和前端视图层的JSF之间的间隙,第一个初稿版本只是针对J2EE,但是在创立规范的过程中很明显的发现大多数的功能是适用于任何Java环境的,包括J2SE。
同时,无论是Guice还是Spring的社区都已经开始努力将 “JSR-330:Java依赖注入作为基本的” (代号 AtInject )作为基本的注入方式。考虑到没有任何新的依赖注入容器实现了实际的注入API,AtInject”和CDI专家组密切合作以确保在依赖注入框架中提出一个通用的解决方案。因此CDI使用了AtInject的注解规范,这就表明每一个CDI的实现都完全符合AtInject的规范,比如Guice和Spring。最终CDI和AtInject都被包含在了J2EE(JSR-316)和几乎所有的J2EE服务器中。

CDI 主要特性
在看示例代码之前,让我们来快速的浏览一遍CDI的一些主要特性

类型安全:CDI根据Java类型来注入对象,用以代替之前的根据名称来注入对象。当类型不能充分唯一判断出注入对象时,我们可以使用@Qualifier注解来指定注入。这可以让编译器更容易发现错误,并提供更便捷的重构。
POJO:几乎每一个Java对象都可以使用CDI来注入!包括EJB和JNDI的资源、持久化对象和已经实现过的工厂方法的任何对象。
可扩展性:每一个CDI容器,我们都能很方便的对其增加扩展性功能,增加的扩展性功能可以运行在每一个CDI容器和无论哪个厂商的J2EE 6 服务器中,这一特性通过精心设计的SPI(服务供应接口)得以实现,并成为JSR-299规范的一部分。
拦截器:它可以很容易的实现你自己的拦截器。因为JSR-299提供了很便捷的方式,他们现在也可以运行在每一个CDI容器和 J2EE 6 服务器中。这是通过指定一个实现了一部分JSR-299的SPI(服务提供接口)来实现的。
可修饰性:它允许动态的扩展已存在的接口实现和代码切面。
事件:CDI指定了一个低耦合的类型安全机制来发送和接受事件。
集成EL表达式:EL 2.2 具有很强的功能和高度的灵活性,CDI提供了对它的插件式支持。
CDI代码示例
让我们一起来看看一个简单的web程序,这个程序可以让你使用一个Web表单发送邮件–特别简单。我们只提供了代码片段,但是应该足够展示CDI的使用重点了。

对于我们的发邮件的程序,我们需要一个具有“application-scoped”标示的MailService对象,这个对象应该是单例模式的(为了保证容器每次获取和注入进来的都是同一个对象)。replyTo的值由 同样具有“application-scoped”标示的ConfigurationService提供。接下来我们可以看到第一次注入, configuration 字段是不能由程序代码设置的,而是由CDI注入的。@Inject注解表示CDI会负责对它的注入。

代码1
@ApplicationScoped
public class MyMailService implements MailService {
private @Inject ConfigurationService configuration;

public send(String from, String to, String body) {
String replyTo = configuration.getReplyToAddress();
… // send the email
}
}
我们的程序可以识别当前用户(注意:他不会尝试进行任何的身份校验)以及当前用户HTTP session的作用域。CDI提供了对Session作用域的支持,在同一个作用域下获取到的是同一个实例对象(在Web应用中)。

默认情况下,CDI对象是不能在JSF表达式中使用的。为了兼容JSF和EL表达式的使用,我们增加了@Named注解:

代码2
@SessionScoped
@Named
public class User {
public String getName() {…}

}

//web页面已经使用JSF实现. 我们建议你使用一个Controller类:
@RequestScoped
@Named
public class Mail {
private @Inject MailService mailService;
private @Inject User user;

private String text; // + getter and setter
private String recipient; // + getter and setter

public String sendMail() {
mailService.send(user.getName(), recipient, text);
return “messageSent”; // forward to ‘message sent’ JSF2 page
}

}
目前为止唯一缺少的就是JSF页面代码了,如下:

sendMail.xhtml
<h:form>
<h:outputLabel value=“Username” for=“username”/>
<h:outputText id=“username” value="#{user.name}"/>
<h:outputLabel value=“Recipient” for=“recipient”/>
<h:inputText id=“recipient” value="#{mail.recipient}"/>
<h:outputLabel value=“Body” for=“body”/>
<h:inputText id=“body” value="#{mail.body}"/>

<h:commandButton value=“Send” action="#{mail.send}"/>
</h:form>
现在我们已经有一个可以正常运行的程序了,让我们来继续探索我们会使用到的CDI功能吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值