我很难理解它们是如何互动的以及它们之间的边界在哪里。 它们是否重叠? 它们之间是否存在冗余?
我知道它们都有关联的注释,但我还没有找到具有简要描述的完整清单。 不确定这是否有助于澄清它们之间的区别或重叠处。
我只是感到困惑。 我(认为我)相当了解EJB,我想我很难理解CDI究竟带来了什么,以及它是如何取代或增强EJB已经提供的功能的。
我很难理解它们是如何互动的以及它们之间的边界在哪里。 它们是否重叠? 它们之间是否存在冗余?
我知道它们都有关联的注释,但我还没有找到具有简要描述的完整清单。 不确定这是否有助于澄清它们之间的区别或重叠处。
我只是感到困惑。 我(认为我)相当了解EJB,我想我很难理解CDI究竟带来了什么,以及它是如何取代或增强EJB已经提供的功能的。
目前的确有点令人困惑,因为Java EE中现在有多个组件模型。它们是CDI、EJB3和JSF托管bean。
CDI是新贵。CDI bean具有依赖注入
、作用域
和事件总线
。CDI bean在注入和作用域方面最灵活。事件总线非常轻量级,非常适合即使是最简单的Web应用程序。此外,CDI还提供了一种名为可移植扩展
的高级功能,它是一种插件机制,供厂商向Java EE提供额外功能,并可在所有实现(Glassfish、JBoss AS、Websphere等)上使用。
EJB3 bean是从旧的遗留EJB2组件模型进行改装的,并且是Java EE中第一个通过注解管理的bean。EJB3 bean具有依赖注入
、声明式事务
、声明式安全性
、池化
、并发控制
、异步执行
和远程调用
。
与CDI bean相比,EJB3 bean的依赖注入不太灵活,并且EJB3 bean没有作用域的概念。但是,EJB3 bean默认情况下是事务性和池化的**,这是CDI选择留在EJB3领域中的两个非常有用的功能。其他提到的项目也不在CDI中可用。虽然EJB3没有自己的事件总线,但它确实有一种特殊类型的bean用于监听消息;这就是消息驱动bean。这可以用于从Java消息系统或任何其他具有JCA资源适配器的系统接收消息。对于简单的事件使用完整的消息传递比CDI事件总线更重量级,而EJB3仅定义了一个监听器,而没有生产者API。
JSF Managed Beans(JSF管理的Bean)是自从JSF被包含在Java EE中以来就一直存在的。它们也具有依赖注入
和作用域
的功能。JSF Managed Beans引入了声明性作用域的概念。最初,这些作用域相当有限,在同一个Java EE版本中,EJB3 Bean已经可以通过注释声明,但JSF Managed Beans仍然必须在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兼容的@ViewScoped,使得CDI确实成为完美超集。更新2:在JSF2.3中,JSF managed beans已被弃用,改为使用CDI managed beans。
对于EJB3和CDI,情况并不那么清晰。EJB3组件模型和API提供了许多CDI没有提供的服务,因此通常情况下无法用CDI替换EJB3。另一方面,CDI可以与EJB3结合使用,例如为EJB添加作用域支持。
专家小组成员和实现了名为CanDI的CDI实现的Reza Rahman经常暗示,与EJB3组件模型相关的服务可以作为一组CDI注解进行适配。如果这样做,Java EE中的所有managed beans都可以变成CDI beans。这并不意味着EJB3会消失或变得过时,而只是它的功能将通过CDI而不是通过EJB自己的注释(如@Stateless和@EJB)公开。
更新
TomEE 和 OpenEJB 的大卫·布莱文斯在他的博客上很好地解释了 CDI 和 EJB 之间的差异和相似之处:CDI,何时使用 EJBs
* 虽然只是一个版本号的增量,EJB3 bean 在很大程度上是一种完全不同类型的 bean:一个简单的 POJO 通过应用一个简单的单一注释成为“托管 Bean”,而不像 EJB2 中的模型,其中每个 Bean 都需要一个笨重且过于冗长的 XML 部署描述符,除了 Bean 必须实现各种极其笨重且大多数毫无意义的组件接口。
** 无状态会话 Bean 通常是被缓存管理的,有状态会话 Bean 通常不是(但它们可以)。对于这两种类型,缓存是可选的,EJB 规范也没有规定要求哪种方式。
CDI: 依赖注入相关。它意味着您可以在任何地方注入接口实现。这个对象可以是任何东西,与EJB无关。这里有一个使用CDI注入随机数生成器的示例(链接),其中没有提到EJB。当您想要注入非EJB服务、不同的实现或算法时,可以使用CDI(因此根本不需要EJB)。
EJB: 您可能已经理解了,但很可能会被@EJB
注释所困扰——它允许您将实现注入到您的服务或其他内容中。主要思想是注入类应该由EJB容器管理。
看起来CDI确实了解EJB,因此在符合Java EE 6标准的服务器中,在您的servlet中您可以同时编写两者。
@EJB EJBService ejbService;
和
@Inject EJBService ejbService;
这可能会让你感到困惑,但这很可能是EJB和CDI之间的唯一桥梁。
当我们谈论CDI时,您可以将其他对象注入到由CDI管理的类中(它们只需要由CDI感知的框架创建)。
CDI还提供了什么......例如,您使用Struts 2作为MVC框架(仅作为示例),在这里受限制,即使使用EJB 3.1-您也不能在Struts操作中使用@EJB
注释,因为它没有被容器管理。但是,当您添加Struts2-CDI插件时,您可以为相同的东西编写@Inject
注释(因此不再需要JNDI查找)。这样可以增强EJB的功能,但正如我之前提到的,您使用CDI注入的内容 - 它是否与EJB相关并不重要,这就是它的优势。
PS. 更新示例链接
阿尔伯特·爱因斯坦:如果你不能简单地解释它,那么你对它的理解还不够深刻
Ejbs和CDI非常容易理解。
Ejbs:
@Stateless
public class CarMaker(){
public void createCar(Specification specs){
Car car = new Car(specs);
}
}
CarMaker被注释为特定的Ejbs范围,因此它是Ejb。
CDI:
它始终是依赖的。让我用一个例子来解释“依赖”:
class Specification {
private String color;
private String model;
//- Getter and Setter
}
Specification
类是CDI,因为它没有用Ejb范围进行注释,而且必须由您的代码初始化,而不是EE框架。
这里需要注意的一点是,由于我们没有对Specification
类进行注释,因此默认情况下会使用@Dependent
注释进行注释。
@Dependent <- By default added
class Specification { ... }
进一步阅读:
您需要更深入地研究Ejbs范围注释和CDI范围注释之间的区别,这将进一步澄清概念。