CDI服务

前言

CDI(Contexts and Dependency Injection 上下文依赖注入),是JAVA官方提供的依赖注入实现,可用于Dynamic Web Module中,将依赖注入IOC/DI上升到容器级别, 它提供了Java EE平台上服务注入的组件管理核心,简化是CDI的目标,让一切均可以被注解被注入。CDI是为解耦而生.如Spring主要用途是AOP.IOC(DI),而CDI除了DI外,AOP功能也是有的.从实际使用上来看,CDI比Spring功能更丰富,更灵活,其代价也是有的,学习成本相对spring较高. java

1.CDI致力于松耦合,强类型.

实现松散耦合的三种方式: 
spring

  1. 部署时候的多态选择,@alternatives 
  2. producer methods在运行时的多态.
  3. 上下文相关的生命周期管理与bean生命周期解耦。

这些技术使客户端和服务器的松散耦合服务。客户端再也不是紧密地绑定到一个接口的一个实现,也不须要管理生命周期实现。这种方法容许有状态的对象看成服务交互。松散耦合使系统更具活力。在之前,框架老是牺牲了类型安全(尤为是经过使用XML描述符,Spring2.5)。 

CDI提供了三个额外的重要措施,进一步松耦合: 
安全

  1. 在业务逻辑层用拦截器技术解耦.
  2. 修饰符(注解)能够用来分离一些业务问题
  3. 用CDI EVENT技术进行解耦事件生产者与消费者.

第二个CDI是强类型的.不管是依赖关系的信息,拦截器,修饰符的Bean,以及CDI event的生产者,消费者等的信息所有都是类型安全的.由编译器进行验证. 
CDI是确确实实没String标识符,如xml配置什么的.好比Spring2.5用XML配置,其实都是字符串,以及"约定大于配置"的概念.在CDI里是没有的.CDI框架不是隐藏,而是没有. 
这种方法的最明显好处就是任何IDE均可以提供自动完成,验证以及最重要的重构!(了解JPA的,能够对比安全类型的查询和JPQL.若是重构代码JPQL是很是麻烦的). 
还有个好处就是你在识别不一样的对象,事件,拦截器能够经过注解而不是字符串名字,这样你能够提高代码质量. 

CDI鼓励开发使用注解.如 
  @Asynchronous,   
  @Secure, 
  @Updated, 
而不是使用复合名称, 
  asyncPaymentProcessor, 
  SecurityInterceptor 
  DocumentUpdatedEvent. 
这也符合代码大全里的一些概念.只不过不用费尽心思考虑命名了,这样更简洁高效. 
注释是可重用的。他们帮助描述系统的不一样部分的共同特质。他们帮助咱们分类和理解代码。他们帮助咱们应对常见问题的经常使用方法。他们使咱们的代码更简洁高效. 
服务器

2.高级功能Producer methods

先贴一段代码,下面都用到框架

 1 import javax.enterprise.inject.Produces;
 2 
 3 @SessionScoped
 4 public class Preferences implements Serializable {
 5 
 6    private PaymentStrategyType paymentStrategy;
 7 
 8    ...
 9 
10    @Produces @Preferred 
11    public PaymentStrategy getPaymentStrategy() {
12        switch (paymentStrategy) {
13            case CREDIT_CARD: return new CreditCardPaymentStrategy();
14            case CHECK: return new CheckPaymentStrategy();
15            case PAYPAL: return new PayPalPaymentStrategy();
16            default: return null;
17        } 
18    }
19 }
20 //注入一个Producer methods
21 @Inject @Preferred PaymentStrategy paymentStrategy;

A:Producer methods的Scope

Producer methods的默认范围是@Dependent. 
从上面代码咱们能够思考一种场景,那就是一个用户会话中有多个PaymentStrategy对象的实例.若是想改变,咱们能够在Producer方法上添加一个@SessionSciped注解. 
如今,若是一个用户调用了这个Producer methods,那么返回的这个PaymentStrategy对象的实例将绑定到会话的上下文.Producer methods不会再实例化另外一个出来. 
async

 

1 @Produces @Preferred @SessionScoped
2 public PaymentStrategy getPaymentStrategy() {
3    ...
4 }

 

注意:Producer methods不继承声明此Producer methods的Bean的Scope. 
其实这里有2个不一样的Bean:Producer methods(至关于一个Bean)以及声明这个生产方法的Bean.
ide

B: Injection into producer methods

在Producer methods一开始的实例有一个潜在的问题
CreditCardPaymentStrategy 的实现使用 Java new 运算符来实例化。学习

private PaymentStrategyType paymentStrategy;

而producer methods应该理解为一个独立的Bean,而paymentStrategy是从Preferences 中用new实例化的.因此咱们应该使用下面这种方式来使用producer methods方法.spa

 1 @Produces @Preferred @SessionScoped
 2 public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
 3                                           CheckPaymentStrategy cps,
 4                                           PayPalPaymentStrategy ppps) {
 5 
 6    switch (paymentStrategy) {
 7       case CREDIT_CARD: return ccps;
 8       case CHEQUE: return cps;
 9       case PAYPAL: return ppps;
10       default: return null;
11    } 
12 }

这里会有问题,若是CreditCardPaymentStrategy 是一个@RequestScope,那这里必然是要发生错误的.由于注入的CreditCardPaymentStrategy Bean实例是request,在@SessionScoped使用前容器就会进行销毁.那么就出错了..net

这是个问题,因此咱们有3种处理方案.

  1.  producer method to @Dependent or @RequestScoped.<最好的方式>
  2. CreditCardPaymentStrategy 更改Scope,但这可能会影响其余的地方,不是很好.
  3. 使用@New限定符,但在CDI 1.1 @New限定符被弃用。CDI鼓励应用程序注入@Dependent范围bean。

C:Use of @New with producer methods<不推荐>

Consider the following producer method:

 

 1 @Produces @Preferred @SessionScoped
 2 public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
 3                                           @New CheckPaymentStrategy cps,
 4                                           @New PayPalPaymentStrategy ppps) {
 5    switch (paymentStrategy) {
 6       case CREDIT_CARD: return ccps;
 7       case CHEQUE: return cps;
 8       case PAYPAL: return ppps;
 9       default: return null;
10    } 
11 }

这将会建立一个新的CreditCardPaymentStrategy依赖实例,传递到生产方法,依赖对象不会被摧毁,直到会话结束。

在CDI 1.1 @New限定符被弃用。CDI鼓励应用程序注入@Dependent范围bean。

D:Disposer methods

一些Procucer methods返回的对象须要显式的破坏。例如,有人须要关闭这个JDBC链接: 

 

1 @Produces @RequestScoped 
2 Connection connect(User user) {
3 
4    return createConnection(user.getId(), user.getPassword());
5 }

 

而在一个相同的类中,disposer method能够进行匹配. 

 

1 void close(@Disposes Connection connection) {
2 
3    connection.close();
4 }

 

说明:在同一个类中,disposer method能够进行匹配类型为Connection 的Procucer methods,从而在 Procucer methods周期结束后进行jdbc的连接关闭. 

以下面这个:

 

 1 import javax.enterprise.context.RequestScoped;
 2 import javax.enterprise.inject.Disposes;
 3 import javax.enterprise.inject.Produces;
 4 import javax.enterprise.inject.spi.InjectionPoint;
 5 import javax.persistence.EntityManager;
 6 import javax.persistence.EntityManagerFactory;
 7 import javax.persistence.PersistenceUnit;
 8 
 9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11 
12 public class Resources {
13 
14     @PersistenceUnit
15     private EntityManagerFactory entityManagerFactory;
16 
17     @Produces
18     @RequestScoped
19     protected EntityManager createEntityManager() {
20 
21         return entityManagerFactory.createEntityManager();
22     }
23 
24     //参数必须对应上面方法的返回值
25     protected void closeEntityManager(@Disposes EntityManager entityManager) {
26 
27         if ( entityManager.isOpen() )
28         {
29             entityManager.close();
30         }
31     }
32 }

 

参考连接:https://my.oschina.net/zhaoqian/blog/263422#h1_1

相关文章
相关标签/搜索