且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在哪里使用 EJB 3.1 和 CDI?

更新时间:2023-01-17 10:47:56

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

Yes, you can freely mix both CDI and EJB and achieve some great results. It sounds like you are using @WebService and @Schedule, which are good reasons for adding EJB to the mix.

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

There's a lot of confusion out there, so here is some general information on EJB and CDI as they relate to each together.

请注意,EJB CDI bean,因此具有 CDI 的所有优点.反过来不是这样(还).所以绝对不要养成思考EJB vs CDI"的习惯,因为这个逻辑真的会转化为EJB+CDI vs CDI",这是一个奇怪的等式.

Note that EJBs are CDI beans and therefore have all the benefits of CDI. The reverse is not true (yet). So definitely don't get into the habit of thinking "EJB vs CDI" as that logic really translates to "EJB+CDI vs CDI", which is an odd equation.

在 Java EE 的未来版本中,我们将继续调整它们.对齐的意思是允许人们做他们已经可以做的事情,而无需顶部的 @Stateful@Stateless@Singleton 批注.

In future versions of Java EE we'll be continuing to align them. What aligning means is allowing people to do what they already can do, just without the @Stateful, @Stateless or @Singleton annotation at the top.

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

Ultimately, EJB and CDI share the same fundamental design of being proxied components. When you get a reference to an EJB or CDI bean, it isn't the real bean. Rather the object you are given is a fake (a proxy). When you invoke a method on this fake object, the call goes to the container who will send the call through interceptors, decorators, etc. as well as take care of any transaction or security checks. Once all that is done, the call finally goes to the real object and the result is passed back through the proxy to the caller.

区别仅在于如何解析要调用的对象.已解决"只是指容器在何处以及如何查找要调用的真实实例.

The difference only comes in how the object to be invoked is resolved. By "resolved" we simply mean, where and how the container looks for the real instance to invoke.

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

In CDI the container looks in a "scope", which will basically be a hashmap that lives for a specific period of time (per request @RequestScoped, per HTTP Session @SessionScoped, per application @ApplicationScoped, JSF Conversation @ConversationScoped, or per your custom scope implementation).

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

In EJB the container looks also into a hashmap if the bean is of type @Stateful. An @Stateful bean can also use any of the above scope annotations causing it to live and die with all the other beans in the scope. In EJB @Stateful is essentially the "any scoped" bean. The @Stateless is basically an instance pool -- you get an instance from the pool for the duration of one invocation. The @Singleton is essentially @ApplicationScoped

因此,从根本上讲,您可以用EJB"bean 做的任何事情都应该可以用CDI"bean 做.在封面下,很难将它们区分开来.除了如何解析实例之外,所有管道都相同.

So in a fundamental level, anything you can do with an "EJB" bean you should be able to do with a "CDI" bean. Under the covers it's awfully hard to tell them apart. All the plumbing is the same with the exception of how instances are resolved.

就容器在执行此代理时将提供的服务而言,它们目前并不相同,但正如我所说,我们正在 Java EE 规范级别进行研究.

They aren't currently the same in terms of the services the container will offer when doing this proxying, but as I say we're working on it at the Java EE spec level.

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

Disregard any "light" or "heavy" mental images you may have. That's all marketing. They have the same internal design for the most part. CDI instance resolution is perhaps a bit more complex because it is slightly more dynamic and contextual. EJB instance resolution is fairly static, dumb and simple by comparison.

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

I can tell you from an implementation perspective in TomEE, there's about zero performance difference between invoking an EJB vs invoking a CDI bean.

当然不要在没有好处的情况下使用 CDI 或 EJB.当您开始需要注入、事件、拦截器、装饰器、生命周期跟踪和诸如此类的东西时,请使用 CDI.这是大多数时间.

Of course don't use CDI or EJB when there is no benefit. Throw in CDI when you start to want injection, events, interceptors, decorators, lifecycle tracking and things like that. That's most the time.

除了这些基础知识之外,还有许多有用的容器服务,如果您通过添加 @Stateful@Stateless@Singleton 就可以了.

Beyond those basics, there are a number of useful container services you only have the option to use if you make your CDI bean also an EJB by adding @Stateful, @Stateless, or @Singleton on it.

这是我何时拆分 EJB 的简短列表.

Here's a short list of when I break out the EJBs.

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

Exposing a JAX-WS @WebService. I'm lazy. When the @WebService is also an EJB, you don't have to list it and map it as a servlet in the web.xml file. That's work to me. Plus I get the option to use any of the other functionality mentioned below. So it's a no-brainer for me.

仅适用于 @Stateless@Singleton.

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

Exposing a JAX-RS resource via @Path. I'm still lazy. When the RESTful service is also an EJB, again you get automatic discovery and don't have to add it to a JAX-RS Application subclass or anything like that. Plus I can expose the exact same bean as an @WebService if I want to or use any of the great functionality mentioned below.

仅适用于 @Stateless@Singleton.

通过 @Startup 在启动时加载.目前在 CDI 中没有与此等效的内容.不知何故,我们错过了在容器生命周期中添加类似 AfterStartup 事件的内容.如果我们这样做了,您就可以拥有一个 @ApplicationScoped bean 来监听它,并且实际上与带有 @Startup@Singleton 相同/代码>.它在 CDI 1.1 的列表中.

Load on startup via @Startup. There is currently no equivalent to this in CDI. Somehow we missed adding something like an AfterStartup event in the container lifecycle. Had we done this, you simply could have had an @ApplicationScoped bean that listened for it and that would be effectively the same as an @Singleton with @Startup. It's on the list for CDI 1.1.

仅适用于 @Singleton.

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

@Asynchronous method invocation. Starting threads is a no-no in any server-side environment. Having too many threads is a serious performance killer. This annotation allows you to parallelize things you do using the container's thread pool. This is awesome.

可用于 @Stateful@Stateless@Singleton.

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

@Schedule or ScheduleExpression is basically a cron or Quartz functionality. Also very awesome. Most containers just use Quartz under the covers for this. Most people don't know, however, that scheduling work in Java EE is transactional! If you update a database then schedule some work and one of them fails, both will automatically cleaned up. If the EntityManager persist call fails or there is a problem flushing, there is no need to un-schedule the work. Yay, transactions.

仅适用于 @Stateless@Singleton.

上述关于事务的说明当然要求您使用 JTA 管理的 EntityManager.您可以将它们与普通的CDI"一起使用,但如果没有容器管理的事务,它会变得非常单调,重复 UserTransaction 提交/回滚逻辑.

The above note on transactions of course requires you to use a JTA managed EntityManager. You can use them with plain "CDI", but without the container-managed transactions it can get really monotonous duplicating the UserTransaction commit/rollback logic.

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

Available to all Java EE components including CDI, JSF @ManagedBean, @WebServlet, @WebListener, @WebFilter, etc. The @TransactionAttribute annotation, however, is available to @Stateful, @Stateless and @Singleton only.

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

The EXTENDED managed EntityManager allows you to keep an EntityManager open between JTA transactions and not lose the cached data. Good feature for the right time and place. Use responsibly :)

仅对 @Stateful 可用.

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

When you need synchronization, the @Lock(READ) and @Lock(WRITE) annotations are pretty excellent. It allows you to get concurrent access management for free. Skip all the ReentrantReadWriteLock plumbing. In the same bucket is @AccessTimeout, which allows you to say how long a thread should wait to get access to the bean instance before giving up.

仅适用于 @Singleton bean.

Available to @Singleton beans only.