Java EE 6 依赖注入提供了统一的 EJB 与 JSF 编程模型

  • Srini Penchikala
  • 张龙

2010 年 1 月 23 日

话题:Java语言 & 开发

依赖注入是最近发布的Java EE 6中的一个主要特性,包含了 JSR 330 与 299,他们都归属于 Java EE 中的企业应用技术类别。JSR 330(Dependency Injection for Java)为依赖注入提供了一个标准、可扩展的 API。JSR 299(Contexts and Dependency Injection for the Java EE Platform 1.0)则建立在 JSR 330 之上,统一并简化了 EJB 与 JSF 编程模型。凭借 JSR 299,Enterprise Bean 可以充当 JSF 应用中的 Managed Bean,同时为 Web 层带来了事务支持。

用于依赖注入的标准化注解

该规范的目标在于为依赖注入提供标准化、可扩展的 API。JSR 330 所定义的一套注解使得被注入的类能够在各种框架间移植,这样开发者就不会再深陷于特定于某个厂商的注解了,比如Spring和 Google Guice等框架。该 JSR 提供的一些注解列举如下:

  • Inject:标识被注入的构造方法、方法以及属性。首先注入构造方法,然后是属性,最后是方法。此外,父类中的属性和方法会在子类前被注入。
  • Qualifier:标识修饰符注解。修饰符是强类型的元素,用于区分同一类型对象的不同使用方式,包括 @Qualifier、@Retention(RUNTIME) 以及 @Documented 注解。
  • Scope:标识范围的注解。
  • Singleton:标识某个类只会生成一个实例。
  • Named:这是一个字符串修饰符。

上下文与依赖注入

上下文与依赖注入(Contexts and Dependency Injection,即 CDI)规范建立在 JSR 330 之上,该规范为依赖注入增加了很多功能,包括自动检测和注入类的配置,同时还提供了一个 API 用于在运行期定义新的注入类,这有助于集成第三方框架。

CDI 统一并简化了 EJB 与 JSF 的编程模型。凭借 CDI,Enterprise Bean 可以在 JSF 应用中充当 JSF Managed Bean 的角色,同时为 Web 层带来了事务支持;Java EE 组件(包括 EJB)还可以绑定到生命周期事件上、也可以进行注入,还能够通过激发和观测事件以松耦合的方式进行交互。这样 EJB 组件就能够访问 Web 层的组件了,如RequestSession和 Application Context 等。

CDI 有助于填平 Java EE 平台 Web 层与 Enterprise 层之间的沟壑。Enterprise 层(借助于 EJB 和 JPA 等技术)对事务性资源提供了强大的支持,而 Web 层则关注于展示。Web 层技术(如 JSF 和 JSP 等)会渲染用户界面并显示内容,但对于事务性资源的处理却显得捉襟见肘。CDI 为 Web 层带来了事务支持,这样我们就能在 Web 应用中轻松访问事务性资源了。比如,借助于 CDI,我们构建的 Java Web 应用能够轻松实现对数据库的访问(由 JPA 提供持久化支持)。

CDI 建立在 Java EE 6 新引入的一个名为 Managed Bean 的概念之上,Managed Bean 用于统一 Java EE 6 中各样各样的 Bean。所谓 Managed Bean,其实就是一个 Java 类,只不过 Java EE 容器会将其看作是受管理的组件。我们还可以在同一个命名空间下为其定义一个名字,就像 EJB 组件那样,不过这是可选的。Managed Bean 还可以使用容器提供的一些服务,这些服务大多与生命周期管理和资源注入有关。其他的 Java EE 技术(如 JSF、EJB 等)和 CDI 都是建立在 Managed Bean 这个基本定义之上,只不过增加了额外的服务而已。比如,JSF Managed Bean 增加了生命周期范围、EJB Session Bean 增加了对事务的支持,而 CDI 则增加了对依赖注入的支持。在 CDI 中,Managed Bean 就是个 Java EE 组件,其可以注入到其他组件中、关联到上下文中或是通过 EL 表达式访问。

CDI 支持的服务提供了如下功能:

  • 有状态组件生命周期的改进,可以绑定到定义良好的上下文中
  • 类型安全的依赖注入方式
  • 借助于事件通知机制的交互
  • 可以将拦截器绑定到组件上(通过 javax.interceptor.Interceptor 和 javax.interceptor.AroundInvoke 注解)

我们可以通过 javax.annotation.ManagedBean 注解或是 CDI 注解(如范围注解和修饰符注解)声明一个 Managed Bean。任何 Bean 都可以绑定到生命周期上下文中,都可以被注入,也都可以通过激发或是观测事件与其他 Bean 进行交互。此外,还可以在 Java 代码中直接调用 Bean,也可以在标准的 EL 表达式中调用 Bean。这样,JSF 页面就可以直接访问 Bean 了,哪怕这个 Bean 是由 EJB 组件(如 Session Bean)实现的也没有问题。

CDI 提供的一些注解列举如下:

  • Model注解会在 MVC 架构下将某个 Java Bean 标识为一个模型对象。这是一个标准化的注解,标识在应用中某个类会担当特定的角色。
  • SessionScoped注解将某个 Bean 的范围设定为 Session。除此之外,还有 RequestScoped、ConversationScoped、ApplicationScoped 以及 Dependent 注解。
  • Produces注解会将某个方法标识为生产方法,这样同一个系统下的另一个 Bean 如果需要该类型的对象就会调用这个生产方法。

JSR 299 的一些参考实现项目有 Apache OpenWebBeans、Resin CanDI以及 JBoss Weld框架。请感兴趣的读者查看 Sun 开发小组发布的系列文章(第一部分第二部分第三部分)以深入了解 JEE 6 中的依赖注入特性。最近DZone还发布了一个关于 CDI 主题的图表

查看英文原文:Dependency Injection in Java EE 6 Provides Unified EJB and JSF Programming Model

Java语言 & 开发