在哪里使用EJB 3.1和CDI?


120

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

我的应用程序具有会话bean,调度程序并使用Web服务。最近,我开始了解Apache TomEE,它支持上下文和依赖注入(CDI)。GlassFish容器还支持CDI。

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

Answers:


408

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

那里有很多混乱,因此这里是有关EJB和CDI的一些常规信息,因为它们彼此相关。

EJB> = CDI

请注意,EJB CDI 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是type,则容器还会查找一个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豆也通过增加一个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-RS Application子类或类似的东西。另外,@WebService如果我想要或使用下面提到的任何出色功能,我都可以公开与之完全相同的bean 。

仅适用于@Stateless@Singleton

启动逻辑

通过启动加载@Startup。CDI中目前没有与此等效的功能。不知何故,我们错过了AfterStartup在容器生命周期中添加类似事件的内容。完成此操作后,您可能只拥有一个@ApplicationScoped侦听它的bean,并且实际上@Singleton与with 相同@Startup。它在CDI 1.1列表中。

仅适用于@Singleton

并行工作

@Asynchronous方法调用。在任何服务器端环境中启动线程都是禁忌。线程太多是严重的性能杀手。该注释使您可以并行化使用容器的线程池执行的操作。这太棒了。

可用来@Stateful@Stateless@Singleton

安排工作

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

仅适用于@Stateless@Singleton

在JTA事务中使用EntityManager

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

适用于所有的Java EE组件,包括CDI,JSF @ManagedBean@WebServlet@WebListener@WebFilter,等@TransactionAttribute注释,但是,是提供给@Stateful@Stateless@Singleton只。

保持JTA的管理 EntityManager

EXTENDED管理EntityManager可以让你保持一EntityManager间开放式JTA的交易,而不是丢失缓存数据。在正确的时间和地点提供好的功能。负责任地使用:)

仅适用于@Stateful

轻松同步

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

仅适用于@Singleton豆类。


32
大卫,天哪:)我想你涵盖了它。
LightGuard 2012年

7
感谢您的回答。您清除了我脑海中的障碍物,并连接了许多点。
2014年

7
到目前为止,这是我读过的关于该主题的最好的解释。它还涵盖了在实际使用中EJB的几乎所有重要方面。做得好!!
nanoquack 2014年

3
这非常容易理解,从严格的法律角度讲,亚当并没有错,但是区别并不明显。规范说EJB实例不是上下文的,但是后来又说对EJB的引用(代理)是上下文的。有状态Bean的生命周期完全由引用(代理)控制,因此,当CDI容器控制该引用(代理)时,其数学结果是一样的-有状态EJB可以有效地上下文关联。
David Blevins 2014年

3
您是在TESLA的午休时间写的吗?
爱迪生

2

如果您确实没有使用ejb 3.1的任何功能,那么答案很简单。但是猜想您的提问表明您怀疑有ejb 3.1概念正在从中受益,而没有意识到它们。一个示例可能是容器可以准备使用slsb池,因此jms和数据库连接不必作为请求的一部分插入

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.