CDI是什么?

CDI(Contexts And Dependency Injection)是JavaEE 6标准中一个规范,将依赖注入IOC/DI上升到容器级别, 它提供了Java EE平台上服务注入的组件管理核心,简化应该是CDI的目标,让一切都可以被注解被注入。

Contexts概念和我们之前在DCI架构中讨论的业务场景不一样,包含有容器技术架构场景的意思,场景包括四种:request (event), session, application, page,而SEAM框架拓展了两个 conversation 和 business process context。


CDI对JSF和EJB模型使用都产生比较大的变化,比如对JSF影响,下面是JSF的一个用来显示的Bean:


import javax.inject.Named;

@Named
public class MessageServerBean {

public String getMessage() {
return "Hello World!";
}
}

使用了@Named来标注,那么在jsp页面中就可以写入标签:

Message is : #{messageServerBean.message}<br>
Message Server Bean is : #{messageServerBean}

达到输出如下结果

Message is : Hello World!
Message Server Bean is : eedemo.MessageServerBean@xxxxxxx

也就是说,@Named标注实际相当于给MessageServerBean取名eedemo.MessageServerBean(当然你也可以显式写一个名称),你就可以直接以messageServerBean对其getter方法进行输出了。

CDI另外一个特点就是将对象在容器中场景生命周期标注出来,如下:


@Named("itemProcessor")
@RequestScoped //表示生命周期是request,每次request请求结束,生命就终止,也可以有Session或 Application等
public class ItemProcessor {

@Inject
private ItemDao itemDao; //表示ItemDao需要被注入

...
}

大家已经看见,其实这些招已经在Spring或我们的Jdonframework中普遍使用,实际是依赖注入的升级版。是一种自动配对auto-wired的注入,不是Spring 1.x中那种手工配置依赖的那种。我在05年文章Ioc容器的革命性优点就提出自动注入划时代的意义。曾经有一段时间还把这作为jdonframework和Spring 1.x区别吹嘘很长时间,现在都已经是平常事了。

CDI还提供了Producer方法,也就是工厂方法的实现,这样在这个对象被注入之前,你可以定制一些你自己的东西。


public class PersonFactory {

@Produces
@RequestScoped
public Person createPerson() {
return new Person();
}
}

但Person被注入到其他需要Person的地方之前,createPerson首先被执行,在这个方法中你能做一些注入之前的准备工作。

CDI还提供Events事件注入,使得异步事件模式能够引入JavaEE中。

事件消息分生产者和消费者,见 Event-Listerner事件监听模式一文。消息生产者定义一个事件:
@Inject
private javax.enterprise.event.Event<User> userEvent;

激活一个事件是:
userEvent.fire(user);

消息监听者也就是消费者,只要标注@Observes ,即可处理发出的事件:


public void observeUserEvent(@Observes User user) {
...
}

事件模式的引入可以为我们实现业务场景融合提供手段,见ZK的CDI应用

@Named
@SessionScoped
public class HelloWorld extends GenericComposer implements Serializable {

@Inject @ComponentId("guestName") Textbox guestName;
@Inject @ComponentId("sayHelloBtn") Button sayHelloBtn;
@Inject @ComponentId("helloWindow") Window helloWindow;

public void sayHello(@Observes @Events("sayHelloBtn.onClick") MouseEvent evt) {
helloWindow.setTitle("Hello " + guestName.getValue());
}
}


不过,这个事件模式和Jdonframework提供的基于领域模型的Domain Events比较类似,但还是有些区别,目前看来,CDI这种事件模式还是组件(userEvent)驱动领域模型(user),不同于JF是领域模型自身发出事件,这两者还是有本质区别,更加突出领域模型作为业务核心的重要位置,而JavaEE6为了强调其技术架构的重要位置,免不了和业务争夺核心位置,这是我们使用者必须注意的,不能死读标准。

CDI还提供了@Decorator和@Interceptor,这涉及AOP和动态组件的概念。有兴趣可仔细研究。

相关资料:
JavaEE6和CDI
From JBoss Seam to CDI (JEE6)
JavaEE 6:EJB3.1新特性

[该贴被banq于2010-03-24 11:41修改过]

cdi必须依赖支持符合JAVAEE6规范的容器,感觉不那么容易使用

2010年03月24日 12:54 "joshuayan"的内容
cdi必须依赖支持符合JAVAEE6规范的容器,感觉不那么容易使用 ...

JavaEE6服务器今年陆续上市, GlassFish 3已经支持,JBoss估计到年中,其实SEAM框架已经主导了JavaEE 6标准。SEAM和GLASSFISH组成联盟了。

至此,Spring和JavaEE终于分道扬镳了,Spring也在发展自己的服务器,企业Java未来变得清晰了:FUTURE OF ENTERPRISE JAVA ...IS CLEAR (JAVA EE WITH/WITHOUT SPRING AND VICE VERSA)

对于实际项目,你得签署两份维护和支持合同,一份是应用服务器,一份是SpringSource. 这实际是让企业用户为难,最后就形成两种结果:
1.部署Spring在其自己的服务器上
2.部署没有Spring的Java EE 6应用(you could build them with Spring support, but deployment to production will be the issue)

The future of Enterprise Java is very clear - full stack Spring or full stack Java EE - but no mix any more.两者再也不会搞在一起了。

在另外一篇文章:LEAN JAVA EE 6 WITHOUT SPRING AND SPRING 3.0 IN JAVA EE 6 WORLD: SUMMARY AND CONCLUSION (EJUG SESSION)
中对JavaEE 6和Spring 3进行了比较,认为Spring不是“约定优于配置”,很多事情都需要声明。Spring 3已经完整支持Java EE 6标准,除了@Stateless。

[该贴被banq于2010-03-25 20:29修改过]

呵呵,总之,觉得做软件得有自己思考,不能跟风,比如过去跟风EJB,现在都是Spring,以后不知道又要跟啥风呵呵。还是秉承jdon的风格,坚持以业务为核心,以业务驱动技术的思想比较切合实际一点。技术just a tool,业务 is the king.

2010年03月24日 23:09 "xmuzyu"的内容
还是秉承jdon的风格,坚持以业务为核心,以业务驱动技术的思想比较切合实际一点。技术just a tool,业务 is the king. ...

完全同意

为了砍柴,我们也需要好好的磨磨板斧阿 :)

最近做一私活,鬼子做好了架构,核心为Seasar,和Spring,JF很类似的一个框架,只不过比起Spring,JF,它要弱得多,虽然以前在国内就没听说过,也没用过,但很快还是搞定了它。技术仅仅是技术,做过几年代码有点点做代码的意识的人都可以很快学会它那框架。业务才是核心。

BTW:我看到Banq的代码里有标注,我不得不个人再鄙视一下Annotations,不论Banq是否同意,我只想表达我的观点,我觉得用了这玩意代码看起来真的是杂乱无章,我理不清调用的先后顺序,我也找不到接口的实现在哪,而且如果还有自定义的Annotaions,它在做什么动作只有写它的人才清楚了,用Annotations对于没有文档的遗留项目,我觉得它就是一噩梦,XML配置烦吗?我觉得EJB2.0的配置很优美呢,Fucking Annotations。

2010年03月25日 18:25 "lendo"的内容
,我不得不个人再鄙视一下Annotations,不论Banq是否同意 ...

比较理解你,初期我也是这样,不过后来随着设计要求提高,Java中也没什么东西可供使唤了,将就着用注解,发现能解决一些问题,不过千万不能过,Annotations至少不能超过Java的代码吧。

>比如过去跟风EJB,现在都是Spring,以后不知道又要跟啥风
现在是NoSQL和云计算,这些技术都是在颠覆JavaEE 或Spring。

借用Johnson在Java EE 6,貌似民主下的虚伪公平一句话:

“到另一个Java EE版本发布的时候,Java的应用情景和现在将有很大的不同,目前还倾向于利用数据库实现大部分应用程序功能,以后我们将看到更多不同的数据存储和不断增多的云部署,我们面临的再也不是这10多年来已经非常熟悉的问题,而是要开启新的篇章。”

现在JavaEE或Spring都倾向于利用关系数据库实现大部分应用程序功能,他们都倾向于保证高一致性,通过JTA事务,JTA或JDBC事务是EJB JPA Hibernate Spring的核心,而这种事务都是借助关系数据库的ACID完成的,在CAP定理中我们讨论了关系数据库ACID只能满足高一致性和容错性,丧失了性能可用性,特别是2PC,跨数据库的两段事务是性能杀手,这也是NoSQL总结分类中谈到。

所以,如果我们把这些都联系起来后,就发现技术发展清晰脉络。企业Java未来是变得清晰了,不再依赖关系数据库,而是根据企业业务应用灵活选择架构,高一致性不再是企业Java固定不变的准则,社会媒体已经渗透到企业IT和营销,企业Java也不再是落后技术的代名词。

[该贴被banq于2010-03-25 20:37修改过]

2010年03月25日 20:24 "banq"的内容
现在JavaEE或Spring都倾向于利用关系数据库实现大部分应用程序功能,他们都倾向于保证高一致性,通过JTA事务,JTA或JDBC事务是EJB JPA Hibernate Spring的核心,而这种事务都是借助关系数据库的ACID完成的 ...

如果完全遵照JEE规范来做企业级应用是没问题的,毕竟企业级应用对数据安全,完整性要求严格,而互联网应用,性能,伸缩性才是王道。因此互联网应用对性能和伸缩性的追求已经使得当当靠JEE规范是无法满足的。就如banq老师说的事务,JEE规范对事务的支持是非常好的,但是要想做一个可伸缩性的JEE的web2.0应用,还需要下很大功夫,还得学会折中,学会取舍。一个系统架构的过程,就是不断取舍,不断折中的过程。

2010年03月25日 22:35 "xmuzyu"的内容
一个系统架构的过程,就是不断取舍,不断折中的过程 ...

是的,正如Rod所说:以后我们将看到更多不同的数据存储(NoSQL)和不断增多的云部署(云架构 云部署),我们面临的再也不是这10多年来已经非常熟悉的问题,而是要开启新的篇章!

2010年03月26日 08:15 "banq"的内容
我们面临的再也不是这10多年来已经非常熟悉的问题,而是要开启新的篇章! ...

Banq,你了不了解腾讯是如何处理几亿用户的数据的?他们都用到了哪些存储技术。如何处理数据大并发和数据同步的。我特别想了解了解。

2010年03月26日 10:20 "lendo"的内容
你了不了解腾讯是如何处理几亿用户的数据的 ...

不太了解,我个人觉得腾讯的处理要比facebook twitter这样Social media要简单,完全采取单纯的划分服务器,腾讯不能算真正社会媒体应用,需要向社会媒体模式转换,由于不在本话题就不多说了。

啥也不想说,从去年12月10日那天,开始感到有点高兴了。

CDI实际是在弥补Web与EJB在生命周期上的鸿沟,昨天 What’s so wrong with EJB’s?讨论这点。

Web的生命周期是request session和application,CDI可以将这些使用@注解标注到EJB上,而EJB有自己生命周期类型:有态Bean,无态Bean和Singleton,比如SLSB是POOL支持,POOL本身就是一种生命周期,所以,这两者就矛盾了。题外话:在jdonframework中Pool和Session和Singleton是并列的,不可能同时存在,而JavaEE6引入CDI以后,因为历史原因,在生命周期管理上出现矛盾了,真是有些尴尬啊。

JSF的可管理Bean的生命周期能够绑定到request, session or application等场景上. 如果Bean中再调用EJB,而EJB有Stateless, Stateful or Singleton三种,那么使用开发者就自己动脑筋如何把Bean生命周期与EJB生命周期联系起来考虑,很头疼哦。有点类似对象和关系数据库的阻抗问题,我们在持久层做这种匹配事情,到前面表现层也要做,事情越搞越复杂,这样的JavaEE不要也罢啊。

lifecycle mismatch和Object relation mismatch已经成为JavaEE面对两大致命杀手。

[该贴被banq于2010-03-29 11:45修改过]

lendo
我和你一起Fuck Annotations

过后,还是要操起Annotations ..

是噩梦, 但是有时又离不开
[该贴被tangshd于2010-04-09 09:27修改过]

学习一下