130

我正在制作一个基于 Java EE 的产品,其中我使用GlassFish 3 和 EJB 3.1。

我的应用程序有会话 bean、调度程序并使用 Web 服务。我最近了解了支持Contexts and Dependency Injection (CDI)的Apache TomEE。GlassFish 容器还支持 CDI。

我可以在不需要 CDI 还没有提供的任何功能的情况下替换会话 bean 吗?如果那样的话,我能得到什么好处?

4

2 回答 2

440

是的,您可以自由地混合 CDI 和 EJB 并取得一些很好的结果。听起来您正在使用@WebServiceand @Schedule,这是将 EJB 添加到混合中的充分理由。

那里有很多混乱,所以这里有一些关于 EJB 和 CDI 的一般信息,因为它们相互关联。

EJB >= CDI

请注意,EJBCDI bean,因此具有 CDI 的所有优点。反过来是不正确的(还)。所以绝对不要养成思考“EJB vs CDI”的习惯,因为这种逻辑实际上转化为“EJB+CDI vs CDI”,这是一个奇怪的等式。

在 Java EE 的未来版本中,我们将继续调整它们。对齐的意思是允许人们做他们已经可以做的事情,只是在顶部没有@Stateful,@Stateless或注释。@Singleton

实施术语中的 EJB 和 CDI

最终,EJB 和 CDI 共享相同的被代理组件的基本设计。当您获得对 EJB 或 CDI bean 的引用时,它并不是真正的 bean。而是给您的对象是假的(代理)。当你在这个假对象上调用一个方法时,调用会转到容器,容器将通过拦截器、装饰器等发送调用,并负责任何事务或安全检查。完成所有这些后,调用最终会转到真实对象,并且结果会通过代理传递回调用者。

不同之处仅在于如何解析要调用的对象。“已解决”是指容器在何处以及如何查找要调用的真实实例。

在 CDI 中,容器在“范围”中查找,该范围基本上是一个存在特定时间段的哈希图(每个请求@RequestScoped、每个 HTTP 会话@SessionScoped、每个应用程序@ApplicationScoped、JSF 会话@ConversationScoped或每个自定义范围实现)。

在 EJB 中,如果 bean 的类型为 ,容器也会查看 hashmap @Stateful。一个@Statefulbean 还可以使用任何上述范围注释,使其与范围内的所有其他 bean 一起生存和死亡。在 EJB@Stateful中,本质上是“任何范围的”bean。这@Stateless基本上是一个实例池——您在一次调用期间从池中获取一个实例。@Singleton本质上是@ApplicationScoped

所以从根本上说,你可以用“EJB”bean 做的任何事情都应该可以用“CDI”bean 做。在幕后,很难将它们区分开来。除了解决实例的方式之外,所有管道都是相同的。

它们目前在执行此代理时容器将提供的服务方面并不相同,但正如我所说,我们正在 Java EE 规范级别进行处理。

性能说明

忽略你可能拥有的任何“轻”或“重”的心理图像。这就是营销。它们大部分具有相同的内部设计。CDI 实例解析可能更复杂一些,因为它更具动态性和上下文关系。相比之下,EJB 实例解析是相当静态、愚蠢和简单的。

我可以从 TomEE 的实现角度告诉您,调用 EJB 与调用 CDI bean 之间的性能差异几乎为零。

默认为 POJO,然后是 CDI,然后是 EJB

当然不要在没有好处的时候使用 CDI 或 EJB。当你开始需要注入、事件、拦截器、装饰器、生命周期跟踪和类似的东西时,就加入 CDI。大多数时候都是这样。

除了这些基础知识之外,还有许多有用的容器服务,只有在您通过添加 、 或 使您的 CDI bean 也成为 EJB 时,您才可以选择@Stateful使用@Stateless@Singleton

以下是我何时分解 EJB 的简短列表。

使用 JAX-WS

公开 JAX-WS @WebService。我很懒。当@WebService也是 EJB 时,您不必列出它并将其映射为web.xml文件中的 servlet。这对我来说是工作。另外,我可以选择使用下面提到的任何其他功能。所以这对我来说是理所当然的。

@Stateless适用于@Singleton

使用 JAX-RS

通过 . 公开 JAX-RS 资源@Path。我还是很懒。当 RESTful 服务也是 EJB 时,您再次获得自动发现,而不必将其添加到 JAX-RSApplication子类或类似的东西中。@WebService另外,如果我想要或使用下面提到的任何强大功能,我可以公开完全相同的 bean 。

@Stateless适用于@Singleton

启动逻辑

启动时通过 加载@Startup。目前在 CDI 中没有与此等效的功能。不知何故,我们错过了AfterStartup在容器生命周期中添加事件之类的东西。如果我们这样做了,你就可以拥有一个@ApplicationScoped监听它的 bean,它实际上与@Singletonwith相同@Startup。它在 CDI 1.1 的列表中。

仅适用于@Singleton

并行工作

@Asynchronous方法调用。在任何服务器端环境中,启动线程都是禁止的。线程过多是严重的性能杀手。此注释允许您并行化您使用容器的线程池所做的事情。这太棒了。

可用于@Stateful和。@Stateless@Singleton

安排工作

@ScheduleorScheduleExpression基本上是一个 cron 或Quartz功能。也非常棒。大多数容器只是为此使用 Quartz。然而,大多数人不知道 Java EE 中的调度工作是事务性的!如果您更新数据库然后安排一些工作并且其中一个失败,则两者都会自动清理。如果EntityManager持久调用失败或刷新有问题,则无需取消计划工作。是的,交易。

@Stateless适用于@Singleton

在 JTA 事务中使用 EntityManager

上面关于事务的注意事项当然要求您使用JTA托管的EntityManager. UserTransaction您可以将它们与普通的“CDI”一起使用,但如果没有容器管理的事务,复制提交/回滚逻辑会变得非常单调。

可用于所有 Java EE 组件,包括 CDI 、JSF、、、、@ManagedBean等。但是,注释仅可用于,并且仅可用于。@WebServlet@WebListener@WebFilter@TransactionAttribute@Stateful@Stateless@Singleton

管理 JTAEntityManager

EXTENDED托管允许您在事务之间EntityManager保持EntityManager打开状态,JTA并且不会丢失缓存的数据。适合时间和地点的好功能。负责任地使用:)

仅适用于@Stateful

轻松同步

当您需要同步时,@Lock(READ)@Lock(WRITE)注释非常好。它允许您免费获得并发访问管理。跳过所有 ReentrantReadWriteLock 管道。在同一个存储桶中是@AccessTimeout,它允许您说明线程在放弃之前应该等待多长时间才能访问 bean 实例。

仅适用于@Singleton豆类。

于 2012-11-22T01:42:13.057 回答
2

如果您真的没有使用 ejb 3.1 的任何功能,答案很简单。但猜猜你的问题表明你怀疑有 ejb 3.1 概念让你受益,但没有意识到它们。一个例子可能是容器可以保持一个 slsb 池随时可用,这样 jms 和数据库连接就不必作为请求的一部分注入

于 2012-11-21T08:18:10.910 回答