Java CDI
CDI(Contexts and Dependency Injection),即上下文依赖注入,它是众多JEE规范中的一个,从JEE6开始CDI正式成为JEE规范,但CDI相关的概念不是新的,依赖注入的概念已经存在了许多年,相关的流行框架包括Spring,Google Guice等。
CDI提供的最基本服务如下:
上下文:将有状态组件的生命周期和交互绑定到定义良好但可扩展的生命周期上下文的能力
依赖注入:以类型安全的方式将组件注入应用程序的能力,包括在部署时选择要注入的特定接口的实现的能力
此外,CDI还提供以下服务:
与表达式语言(EL)集成,允许在JavaServer Faces页面或JavaServer Pages页面中直接使用任何组件
装饰注入组件的能力
使用类型安全拦截器绑定将拦截器与组件相关联的能力
事件通知模型
除了Java Servlet规范定义的三个标准范围(请求,会话和应用程序)之外的Web会话范围
完整的服务提供程序接口(SPI),允许第三方框架在Java EE 6环境中完全集成
CDI的一个主要主题是松耦合。CDI执行以下操作:
通过定义良好的类型和限定符来解耦服务器和客户端,以便服务器实现可能会有所不同
通过执行以下操作来解耦协作组件的生命周期:
通过自动生命周期管理使组件具有上下文功能
允许有状态组件像服务一样进行交互,纯粹是通过消息传递
通过事件将消息生成器与消费者完全分离
通过Java EE拦截器解耦正交问题
依赖注入
依赖注入(DI)是指向软件组件提供外部依赖的过程。DI可以帮助您的代码在架构上保持纯粹。
它通过提供一种注入依赖关系的一致方式,通过接口和测试驱动开发来帮助设计。例如,数据访问对象(DAO)可能依赖于数据库连接。
您可以注入它,而不是使用JNDI查找数据库连接。
考虑像CDI这样的DI框架的一种方法是考虑将JNDI翻出来。DI容器注入那些依赖对象,而不是查找其他对象以完成其工作(依赖项)所需的对象。这就是所谓的好莱坞原则,“别叫我们”(查找对象),“我们会叫你”(注入对象)。
如果您使用过CRC卡,则可以将依赖关系视为协作者。协作者是另一个对象需要执行其角色的对象,例如DAO(数据访问对象)需要JDBC连接对象。
CDI代码示例
这个程序可以让你使用一个Web表单发送邮件–特别简单。我们只提供了代码片段,但是应该足够展示CDI的使用重点了。
对于我们的发邮件的程序,我们需要一个具有“application-scoped”标示的MailService对象,这个对象应该是单例模式的(为了保证容器每次获取和注入进来的都是同一个对象)。replyTo的值由 同样具有“application-scoped”标示的ConfigurationService提供。接下来我们可以看到第一次注入, configuration 字段是不能由程序代码设置的,而是由CDI注入的。@Inject注解表示CDI会负责对它的注入。
@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
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
我们的程序可以识别当前用户(注意:他不会尝试进行任何的身份校验)以及当前用户HTTP session的作用域。CDI提供了对Session作用域的支持,在同一个作用域下获取到的是同一个实例对象(在Web应用中)。
默认情况下,CDI对象是不能在JSF表达式中使用的。为了兼容JSF和EL表达式的使用,我们增加了@Named注解:
@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
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
缺少的就是JSF页面代码了,如下:
<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>