作者 Charles Humble 译者 张龙 发布于 2009年11月23日 下午11时24分
前不久Red Hat的JBoss部门发布了Weld1.0.0——Java EE 6对JSR-299(Java EE的上下文与依赖注入, 即Contexts and Dependency Injection for Java EE,后文简称为CDI)的参考实现。Sun GlassFish Application Server v3和即将发布的JBoss AS 5.2.0都使用了Weld实现,然而Weld并不需要完整的应用服务器。它可以运行在Servlet容器内如Jetty 6.1或是Tomcat 6,同时也能用于Java SE 5.0+。为了阐明后一点, Weld发布包中还带有一个示例性的控制台应用及一个Swing应用示例。
在JSR-299草案首次发布后,Google与SpringSource又联合提交了JSR-330,旨在标准化“一个久经考验、无可辩驳的注解集以使得注入类能够跨越多个框架”,因此在我碰到CDI规范的领导者Gavin King时就迫不及待地询问他JSR-330对CDI有何影响。
CDI现在使用JSR-330所定义的注解来声明注入点。这种影响是微乎其微的,因为330所使用的模型基本上与299大同小异。归结起来,只是注解名有所区别罢了。
要知道330并没有定义完整的依赖注入方案。它只定义了带有修饰符的注入点而已,其他的都没有定义。
InfoQ: CDI和EJB是如何处理EE 6所引入的Managed Bean模型的?
新的Managed Bean规范是JSR-299的工作成果(在规范的早期草案中我们称之为“简单Web Bean”)。简单Web Bean支持依赖注入、EL名字与拦截器,但却没有EJB那些编程约束。
Managed Bean规范引起了很多争议,Red Hat说我们确实需要支持普通Java类的注入,而其他EE涉众则表示对299定义这样一个新EE“组件”的行径感到非常不爽。
经过多次讨论后,我们认为这种“简单”组件的想法应该自成一个规范,以此构成所有其他EE组件编程模型的基础,包括EJB等等。这是一个非常棒的愿景,我们都很赞同这个观点,但EE 6并没有完全实现它。
最后的结果是:CDI可以用在普通的Java类(现在叫做“Managed Bean”)以及EJB上。现在的EJB可以看作是一种特殊的Managed Bean,只不过有一些额外的编程约束和功能。这种编程模型能够极大地降低新用户学习EE的曲线。
InfoQ: EJB还需要自己的组件模型么?
我认为EE平台的未来发展方向是逐渐将EJB特有的功能通用化,将其应用在所有的Managed Bean上。举个例子,为何不是所有的Managed Bean都支持@TransactionAttribute和@RolesAllowed呢?简直没有道理嘛。
然而EJB在为消息传输定义端点、远程与异步方法调用、定时器等领域还是有一席之地的。在这些情况下,EJB生命周期模型还是非常有意义的。
InfoQ: Seam为JSF 2和CDI创造了灵感。在JSF中修复这些问题要比在Seam中解决好在哪呢?
在尽力透明化用户体验的过程中,我们从来都没有真正满意过。用户总是注意到何时在使用JSF的特性,何时在使用本应放在JSF中的Seam特性。
CDI来源于Red Hat的开源Seam框架,从广义上来讲,它将Seam的编程模型标准化为Java EE6的编程模型。CDI实现了Java EE 6的3个主要目的。首先,它提供了声明的方式来管理绑定到上下文组件的范围、状态与生命周期。其次,它为平台提供了标准化、注解驱动、类型安全的依赖注入 框架,方式类似于Google Guice。最后,它为Java EE平台的扩展开发提供了Service Provider Interface(SPI)。
CDI的Service Provider Interface已经成为Java EE可扩展性的一个关键组成部分,而可扩展性则是Java EE 6的一个中心议题。JSR-316规范说到:
...我们相信大家都很渴望将这些技术用于JavaEE应用服务器之上,或是以插件的形式使用。通过增加更多的扩展点和服务供应商接口,其他技术就可以插件的形式用于平台实现了,这么做既整洁又高效,对于 开发者来说使用起来也是非常简单的,就像是内置于平台上的设备一样。
这一点大家可以从下一版的Seam(也就是Seam 3)中看到,Seam 3将CDI作为其核心引擎并使用CDI ServiceProvider Interface提供了CDI中并没有涵盖的众多特性,如BPM集成、Drools集成、PDF与Email模板支持以及Excel生成等等。这些扩展 (也包括第三方厂商提供的其他扩展)可以运行在支持JSR-299的任何环境中,也包括任何Java EE 6环境。CDI规范说到:
可移植的扩展可以通过如下方式与容器集成:
• 提供自己的Bean、拦截器和装饰器。
• 通过依赖注入服务将依赖注入到自己的对象中。
• 为客户化的范围(custom scope)提供一个上下文实现。
• 通过外部注解增强或是提供基于注解的元数据。
Gavin King说到:
CDI和JSF 2的出现预示了Seam的新方向。
在Seam 2中,我们花费了巨大的精力填补JSF的漏洞,结果造成了没有时间集成那些非常吸引我们的表示层技术。JSF 2可以让我们将精力放在其他领域中。
最重要的是,CDI现在提供了一个核心“引擎”,可以在所有的EE 6应用服务器之间移植,甚至还可以用在Tomcat、Jetty和Resin上。该核心并不依赖于任何特定的表示层技术。其所拥有的仅仅是为可移植扩展开 发者所提供的一套定义良好的SPI。该SPI作为整个生态系统的根基。如果你是一位框架开发者,那现在就会明确要想将框架与CDI及EE环境集成起来(通 过扩展)需要做哪些事情。这也许是CDI最令人激动的特性了。
Seam 3将成为一套CDI可移植扩展,可以用在任何应用服务器上并向CDI编程模型提供扩展,同时能与我们感兴趣的其他技术进行集成。
JBoss CTO Mark Little说CDI和Seam将是其所有项目和平台的未来发展方向:
目前团队正与这些项目和平台(如ESB和SOA-P)紧密合作以确保新版Seam能考虑到其特定的需求。重要的是,一些项目已经认为Seam是其正确的选择,甚至都不用做任何修改,因此紧密与快速的集成要比想象的更容易一些。
King也确认了这一点并说到:
RedHat已经成功将Seam应用到其所开发的一些项目当中了。CDI将Seam的核心功能放在了坚固的根基之上,而我们对CDI的实现Weld是个更加专注 且测试良好的基础设施。这意味着我们可以将Weld应用在Seam 2不适合的各种领域中,而这与构建Web站点无关。
除了Red Hat外还有很多其他的CDI实现也即将破茧成蝶。Resin的创建者Caucho Technology拥有一个实现(CanDI),而Resin容器本身也在内部大量使用了CDI。Apache也正致力于一个名为 OpenWebBeans的实现,Granite DS也有一个实现,可以将CDI应用在Flex应用中, 如下:
我们认为JCDI非常适合于事件驱动架构的Flex RIA。JCDI应用非常整洁,尽管JBoss Seam提供了大量的特性,但他们没必要再开发一个RIA前端了。