前言

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较高.

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

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

  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

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

 import javax.enterprise.inject.Produces;

 @SessionScoped
public class Preferences implements Serializable { private PaymentStrategyType paymentStrategy; ... @Produces @Preferred
public PaymentStrategy getPaymentStrategy() {
switch (paymentStrategy) {
case CREDIT_CARD: return new CreditCardPaymentStrategy();
case CHECK: return new CheckPaymentStrategy();
case PAYPAL: return new PayPalPaymentStrategy();
default: return null;
}
}
}
//注入一个Producer methods
@Inject @Preferred PaymentStrategy paymentStrategy;

A:Producer methods的Scope

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

 @Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy() {
...
}

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

B: Injection into producer methods

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

private PaymentStrategyType paymentStrategy;

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

 @Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
CheckPaymentStrategy cps,
PayPalPaymentStrategy ppps) { switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}

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

这是个问题,所以我们有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:

 @Produces @Preferred @SessionScoped
public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps,
@New CheckPaymentStrategy cps,
@New PayPalPaymentStrategy ppps) {
switch (paymentStrategy) {
case CREDIT_CARD: return ccps;
case CHEQUE: return cps;
case PAYPAL: return ppps;
default: return null;
}
}

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

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

D:Disposer methods

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

 @Produces @RequestScoped
Connection connect(User user) { return createConnection(user.getId(), user.getPassword());
}

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

 void close(@Disposes Connection connection) {

    connection.close();
}

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

如下面这个:

 import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class Resources { @PersistenceUnit
private EntityManagerFactory entityManagerFactory; @Produces
@RequestScoped
protected EntityManager createEntityManager() { return entityManagerFactory.createEntityManager();
} //参数必须对应上面方法的返回值
protected void closeEntityManager(@Disposes EntityManager entityManager) { if ( entityManager.isOpen() )
{
entityManager.close();
}
}
}

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

 

CDI服务的更多相关文章

  1. JAVA CDI 学习(4) - @Alternative/@Default/@Any & Extension

    前面几节学习到的CDI内容,基本上都是hard-code,以硬编码的方式在代码里指定注入类型,这并非依赖注入的本意,依赖注入的优势之一在于“解耦”,这一节我们将学习如何利用配置来动态注入的类型及属性初 ...

  2. JAVA CDI 学习(1) - @Inject基本用法

    CDI(Contexts and Dependency Injection 上下文依赖注入),是JAVA官方提供的依赖注入实现,可用于Dynamic Web Module中,先给3篇老外的文章,写得很 ...

  3. 第二章 自己的框架WMTS服务,下载数据集成的文章1

    在构建数据源下载文件的叙述性说明第一步 如此XML结构体 <?xml version="1.0" encoding="utf-8"?> <on ...

  4. Analysis CDI

    CDI是一组服务,它们一起使用,使开发人员可以轻松地在Web应用程序中使用企业bean和JavaServer Faces技术.CDI设计用于有状态对象,还有许多更广泛的用途,允许开发人员以松散耦合但类 ...

  5. CDI Features(EL(SPEL),Decorator,Interceptor,Producer)

    一.EL(SPEL) EL 1.概述:EL是JSP内置的表达式语言,用以访问页面的上下文以及不同作用域中的对象 ,取得对象属性的值,或执行简单的运算或判断操作.EL在得到某个数据时,会自动进行数据类型 ...

  6. CDI的分析

    CDI是一组服务,它们一起使用,使开发人员可以轻松地在Web应用程序中使用企业bean和JavaServer Faces技术.CDI设计用于有状态对象,还有许多更广泛的用途,允许开发人员以松散耦合但类 ...

  7. servlet cdi analysis

    CDI中最令人兴奋的功能是允许每个人在Java EE平台中编写强大的扩展性功能,甚至于改变其核心本身.这些扩展性功能是可以完全移植到任何支持CDI的环境中. CDI的一些主要特性 1.类型安全:CDI ...

  8. CDI Event解析

    CDI(Contexts And Dependency Injection)是JavaEE 6标准中一个规范,将依赖注入IOC/DI上升到容器级别, 它提供了Java EE平台上服务注入的组件管理核心 ...

  9. 使用Quarkus在Openshift上构建微服务的快速指南

    在我的博客上,您有机会阅读了许多关于使用Spring Boot或Micronaut之类框架构建微服务的文章.这里将介绍另一个非常有趣的框架专门用于微服务体系结构,它越来越受到大家的关注– Quarku ...

随机推荐

  1. C3垂直居中均分

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  2. Invalid character found in method name. HTTP method names must be tokens

      o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header Note: further occurrenc ...

  3. 常用JS对象的方法总结

    String 方法 描述 charAt() 返回在指定位置的字符. charCodeAt() 返回在指定的位置的字符的 Unicode 编码. concat() 连接字符串. indexOf() 检索 ...

  4. angularJS---自定义过滤器

    AngularJS另一个特点就是提供了过滤器,可以通过操作UNIX下管道的方式,操作数据结果. 通过使用管道,可以便于双向的数据绑定中视图的展现. 过滤器在处理过程中,将数据变成新的格式,而且可以使用 ...

  5. 手机端实现fullPage——全屏滚动效果

    封装了一个小插件模拟fullPage的全屏滚动效果,比较简单. 特点: 1.  纯js实现,小巧轻便. 2.  兼容性好.苹果.安卓都没问题,暂时没遇到问题机型. 缺点: 1.  仅封装了基础功能,H ...

  6. man.go 阅读笔记

    import (     "flag"     "fmt"     "github.com/Sirupsen/logrus"     &qu ...

  7. 新版知乎登录之post请求

    前言 在上一篇文章中给大家讲解了requests发送post请求的几种方式,并分析了一些使用陷阱. 疑惑 在文章发表之后,有朋友给我留言说,知乎登录就没有使用提交Form表单(application/ ...

  8. 获得指定数据库中指定块表中所有实体的id

    该函数也使用外部指定图纸中的数据库中的块 Int getIdsByDwgBlkName(AcDbDatabase *pDwg, CString strBlkName, AcDbObjectIdArra ...

  9. 【bzoj 3309 】 DZY Loves Math

    Description 对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0.给定正整数a,b,求 ...

  10. bzoj 4318 OSU 概率期望dp

    可以发现:f[i]转移到f[i+1]只和最后一串1的长度和平方有关, 因为如果新加的位置是1,贡献就是(x+1)^3-x^3=3x^2+3x+1,否则为0: 所以对于每一个位置,处理出期望的f,x和x ...