我正在制作一个基于 Java EE 的产品,其中使用了 玻璃鱼3和 EJB 3.1。
我的应用程序有 会话豆,一个调度程序和使用 Web 服务。我最近开始了解支持 上下文和依赖注入(CDI)的 Apache TomEE。GlassFish 容器还支持 CDI。
在不需要任何 CDI 也没有提供的特性的情况下,是否可以替换会话 bean?如果那样的话,我能得到什么好处呢?
如果您确实没有使用 ejb 3.1的任何特性,那么答案很简单。但是猜测你的问题表明你怀疑有 ejb 3.1的概念,你从中受益却没有意识到它们。一个例子可能是容器可以保持一个可以使用的 slsb 池,这样 jms 和数据库连接就不必作为请求的一部分注入
是的,您可以自由地混合使用 CDI 和 EJB,并取得一些很好的结果。听起来您正在使用 @WebService和 @Schedule,这是将 EJB 添加到混合中的好理由。
@WebService
@Schedule
这里有很多混淆,因此这里有一些关于 EJB 和 CDI 的一般信息,因为它们彼此关联在一起。
请注意,EJB 是 CDI bean 因此具有 CDI 的所有优点。相反的情况(尚未)发生。所以绝对不要养成“ EJB vs CDI”的习惯,因为这个逻辑实际上翻译成“ EJB + CDI vs CDI”,这是一个奇怪的等式。
在未来的 JavaEE 版本中,我们将继续对齐它们。对齐的意思是允许人们做他们已经可以做的事情,只是没有在顶部的 @Stateful,@Stateless或 @Singleton注释。
@Stateful
@Stateless
@Singleton
最终,EJB 和 CDI 共享作为代理组件的相同基本设计。当您获得对 EJB 或 CDI bean 的引用时,它不是真正的 bean。相反,你得到的对象是一个假的(代理)。当您在这个假对象上调用一个方法时,调用将发送到容器,容器将通过拦截器、装饰器等发送调用,并负责任何事务或安全检查。完成所有这些操作之后,调用最终转到实际对象,结果通过代理传递回调用方。
区别只在于如何解析要调用的对象。我们所说的“解决”只是指容器在何处以及如何查找要调用的实例。
在 CDI 中,容器看起来是在一个“作用域”中,这个作用域基本上是一个散列映射,存在一段特定的时间(每个请求 @RequestScoped,每个 HTTP Session @SessionScoped,每个应用程序 @ApplicationScoped,JSF Conversation @ConversationScoped,或者每个自定义作用域实现)。
@RequestScoped
@SessionScoped
@ApplicationScoped
@ConversationScoped
在 EJB 中,如果 bean 的类型是 @Stateful,那么容器也会查看散列表。@Stateful bean 还可以使用上述任何范围注释,导致它与范围中的所有其他 bean 一起生存和消亡。在 EJB@Stateful中,本质上是“任意作用域”的 bean。@Stateless基本上是一个实例池——在一次调用期间从池中获得一个实例。@Singleton基本上是 @ApplicationScoped
因此,在基本层面上,您可以使用“ EJB”bean 做任何事情,您应该能够使用“ CDI”bean 做任何事情。在被子下面很难分辨他们。除了如何解析实例之外,所有管道都是相同的。
它们目前在执行这种代理时容器将提供的服务方面并不相同,但是正如我所说的,我们正在 JavaEE 规范级别上进行这方面的工作。
忽略你可能有的任何“轻”或“重”的心理图像。这都是市场营销。它们大部分都有相同的内部设计。CDI 实例解析可能更复杂一些,因为它稍微更动态和上下文相关。相比之下,EJB 实例解析相当静态、简单。
我可以从 TomEE 的实现角度告诉您,调用 EJB 与调用 CDI bean 之间的性能差异几乎为零。
当然不要在没有好处的情况下使用 CDI 或 EJB。当您开始想要注入、事件、拦截器、装饰器、生命周期跟踪等等的时候,可以使用 CDI。大部分时间都是这样。
除了这些基础知识之外,还有许多有用的容器服务,只有通过在其上添加 @Stateful、 @Stateless或 @Singleton使 CDI bean 也成为一个 EJB 时,您才能选择使用这些容器服务。
下面是我什么时候打开 EJB 的简短列表。
暴露 JAX-WS @WebService。我很懒。当 @WebService也是 EJB 时,您不必列出它并将它映射为 web.xml文件中的 servlet。对我来说就是工作。另外,我还可以选择使用下面提到的任何其他功能。所以对我来说这是显而易见的。
web.xml
只适用于 @Stateless和 @Singleton。
通过 @Path公开 JAX-RS 资源。我还是很懒。当 RESTful 服务也是一个 EJB 时,您将再次获得自动发现,并且不必将其添加到 JAX-RS Application子类或类似的任何东西。另外,如果我想要或者使用下面提到的任何伟大功能,我可以公开与 @WebService完全相同的 bean。
@Path
Application
通过 @Startup加载启动。目前在 CDI 中还没有类似的东西。不知何故,我们错过了在容器生命周期中添加类似于 AfterStartup事件的内容。如果我们这样做了,您只需要有一个 @ApplicationScoped bean 来监听它,并且这将有效地与 @Startup的 @Singleton相同。在 CDI 1.1的清单上。
@Startup
AfterStartup
只适用于 @Singleton。
@Asynchronous方法调用。在任何服务器端环境中,启动线程都是不允许的。线程太多会严重影响性能。此注释允许您使用容器的线程池并行处理所做的事情。太棒了。
@Asynchronous
适用于 @Stateful,@Stateless和 @Singleton。
@Schedule或 ScheduleExpression基本上是一个 cron 或 Quartz功能。也很棒。大多数容器只是在盖子下使用石英。然而,大多数人并不知道 JavaEE 中的调度工作是事务性的!如果你更新一个数据库,然后安排一些工作,其中一个失败,两者都将自动清理。如果 EntityManager持久调用失败或者刷新出现问题,就没有必要取消工作计划。耶,交易。
ScheduleExpression
Quartz
EntityManager
上面关于事务的说明当然要求您使用 JTA管理的 EntityManager。您可以将它们与普通的“ CDI”一起使用,但是如果没有容器管理的事务,那么复制 UserTransaction提交/回滚逻辑就会变得非常单调。
JTA
UserTransaction
适用于所有 JavaEE 组件,包括 CDI、 JSF@ManagedBean、 @WebServlet、 @WebListener、 @WebFilter等。然而,@TransactionAttribute注释仅适用于 @Stateful、 @Stateless和 @Singleton。
@ManagedBean
@WebServlet
@WebListener
@WebFilter
@TransactionAttribute
EXTENDED托管的 EntityManager允许您在 JTA事务之间保持 EntityManager打开,并且不会丢失缓存的数据。对于正确的时间和地点来说,这是一个很好的特性。负责任地使用:)
EXTENDED
只适用于 @Stateful。
当需要同步时,@Lock(READ)和 @Lock(WRITE)注释非常优秀。它允许您免费获得并发访问管理。跳过所有 ReentrantReadWriteLock 管道。在同一个 bucket 中还有 @AccessTimeout,它允许您说明线程在放弃之前应该等待多长时间才能获得对 bean 实例的访问。
@Lock(READ)
@Lock(WRITE)
@AccessTimeout
仅供 @Singleton豆使用。