目前确实有点令人困惑,因为现在 Java EE 中有多个组件模型。它们是 CDI、EJB3 和 JSF 托管 Bean。
CDI 是新来的。 CDI bean 具有 dependency injection、scoping 和 event bus。 CDI bean 在注入和作用域方面是最灵活的。事件总线非常轻量级,非常适合最简单的 Web 应用程序。除此之外,CDI 还公开了一个非常高级的功能,称为portable extensions,这是一种插件机制,供供应商为 Java EE 提供额外的功能,可以在所有实现(Glassfish、JBoss AS、Websphere)上使用等)。
EJB3 bean 是从旧的遗留 EJB2 组件模型改进而来的*,并且是 Java EE 中第一个通过注释管理 bean 的 bean。 EJB3 bean 具有 dependency injection、declarative transactions、declarative security、pooling、concurrency control、asynchronous execution 和 remoting。
EJB3 bean 中的依赖注入不如 CDI bean 灵活,而且 EJB3 bean 没有范围的概念。但是,EJB3 bean 是事务性的,默认情况下是池化的**,这是 CDI 选择留在 EJB3 域中的两个非常有用的东西。其他提到的项目在 CDI 中也没有。虽然 EJB3 没有自己的事件总线,但它确实有一种特殊类型的 bean 用于侦听消息;消息驱动的bean。这可用于从 Java 消息传递系统或任何其他具有 JCA 资源适配器的系统接收消息。对简单事件使用完整的消息传递比 CDI 事件总线要重得多,而且 EJB3 只定义了一个侦听器,而不是一个生产者 API。
JSF Managed Beans 自从 JSF 被包含在 Java EE 中就已经存在了。它们也有 dependency injection 和 scoping。 JSF Managed Beans 引入了声明性作用域的概念。最初,范围相当有限,并且在相同版本的 Java EE 中,EJB3 bean 已经可以通过注释声明,JSF 托管 Bean 仍然必须在 XML 中声明。当前版本的 JSF Managed Beans 最终也是通过注释声明的,并且范围通过视图范围和创建自定义范围的能力进行扩展。视图范围会记住对相同页面的请求之间的数据,这是 JSF Managed Beans 的一项独特功能。
除了视图范围之外,Java EE 6 中的 JSF Managed Beans 几乎没有什么用处。不幸的是,CDI 中缺少视图范围,否则 CDI 将成为 JSF Managed Beans 提供的完美超级集. 更新:在 Java EE 7/JSF 2.2 中添加了 CDI compatible @ViewScoped,使得 CDI 确实是完美的超集。 更新 2:在 JSF2.3 中,JSF 托管 bean 已被弃用,取而代之的是 CDI 托管 bean。
对于 EJB3 和 CDI,情况并不那么明确。 EJB3 组件模型和 API 提供了许多 CDI 不提供的服务,因此通常 EJB3 不能被 CDI 替代。另一方面,CDI 可以与 EJB3 结合使用 - 例如。为 EJB 添加范围支持。
Reza Rahman,一个名为 CanDI 的 CDI 实现的专家组成员和实现者,经常暗示与 EJB3 组件模型相关的服务可以被改造为一组 CDI 注释。如果发生这种情况,Java EE 中的所有托管 bean 都可能成为 CDI bean。这并不意味着 EJB3 消失或过时,只是它的功能将通过 CDI 而非 EJB 自己的注解(如 @Stateless 和 @EJB)公开。
更新
TomEE 和 OpenEJB 的 David Blevins 在他的博客上很好地解释了 CDI 和 EJB 之间的异同:CDI, when to break out the EJBs
*
尽管它只是版本号的增加,但 EJB3 bean 在很大程度上是一种完全不同的 bean:一个简单的 pojo,通过应用一个简单的单个注解变成一个“托管 bean”,而 EJB2 中的模型是一个重量级和过度的每个 bean 都需要详细的 XML 部署描述符,此外还需要 bean 实现各种极其重量级且大部分无意义的组件接口。
** 无状态会话 bean 通常是池化的,有状态会话 bean 通常不是(但它们可以是)。因此,对于这两种类型,池都是可选的,EJB 规范并没有强制要求。