博客背景
因为在公司产品中用到Java EE中的CDI,所以需要做一个探究,以满足业务需要,通过一段时间的学习,将一些基本用法讲出来,
希望与各位网友一起讨论
概述
定义:Contextual Dependency Injection,上下文依赖注入。
context,上下文,可以绑定生命周期,可以与有状态的组件交互。
DI,依赖注入,以类型安全的方式注入一个组件到应用中去,包括指定特定实现注入。
CDI还提供了以下的服务:
- 集成EL语言,允许组件直接在JSF和JSP中使用。
- 可以修饰注入的组件。
- 能够使用类型安全的拦截器去和组件关联
- 一个事件通知模型
- 提供的作用域有:request,session,qpplication,conversation
- 有完整的SPI(Service Provider Interface),允许第三方集成
(CDI提供的服务这里只讲一些常见和常用到的,其他一下用法可以参考CDI官方文档)
为什么用CDI
CDI主要是为了解耦,之前我们需要在一个类中new另外一个类,代码耦合度很高,比如:
public class Student {
Teacher teacher = new Teacher();
}
当我们用了CDI之后,可以这样写:
public class Student {
@Inject
Teacher teacher;
}
这样我们就把new的这个动作交给容器了,并且使容器自动管理bean的生命周期,实现了component之间的松耦合
想要实现CDI管理的bean,需要满足下列全部条件(这里不包括JSF组件):
- 如果是内部类的话,只能是静态内部类
- 是一个具体的类或是被@Decorator修饰
- 没有被EJB的注解标注或不是ejb-jar.xml中的EJB bean
- 合适的构造器,下列条件其中之一:
- 无参构造器
- 用@Inject定义的一个构造器
可以注入的bean有哪些
- 几乎是任何一个Java类
- Session beans
- Java EE的资源:数据源,JMS,Queue,连接工厂
- 持久化上下文(JPA,EntityManager Objects)
- 生产者属性
- 返回生产值方法的实体
- web service引用
- 远程企业级bean的引用
如何使用CDI
上面提到的那种是常见的
当一个接口,有多个实现类时,怎么让容器知道注入哪一个呢?
1. 一个是用@Named直接指定类的名字,官方不推荐,这里不作展示
2. 一个是用@Qualifier的方式,请看代码:
IStudent的写法:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface IStudent {
}
然后Student实现Person接口
然后由在另外一个需要用到的类里注入
@Inject
@IStudent
private Person student;
CDI应用的配置
CDI必须有beans.xml,文件可以为空,但必须有。
1. 对一个web应用,这个文件必须在WEB-INF中。
2. 对EJB模块或JAR文件,必须在META-INF下。