我应该使用@EJB还是@Inject?

167

我找到了这个问题:什么是 @Inject 和 @EJB 的区别,但我并没有更明白。

@EJB 是一种旧的注入方式吗?在使用此注解时,是否由 EJB 容器进行注入,而使用 @Inject 则使用新的 CDI 框架进行注入?这是两者之间的区别,如果是这样,我应该使用 @Inject 而不是 @EJB 吗?

9个回答

198
@EJB是用于注入EJB的,已经有一段时间了。而@Inject可以注入任何托管bean,并且是新的CDI规范的一部分(自Java EE 6以来)。
在简单的情况下,您可以简单地将@EJB更改为@Inject。在更复杂的情况下(例如,当您严重依赖于@EJB的属性,如beanNamelookupbeanInterface)时,为了使用@Inject,您需要定义一个@Producer字段或方法。
以下资源可能有助于理解@EJB@Produces之间的区别以及如何充分利用它们:
Antonio Goncalves的博客:
CDI第一部分
CDI第二部分
CDI第三部分

JBoss Weld文档:
CDI和Java EE生态系统

StackOverflow:
根据条件注入@EJB bean


4
为什么在循环依赖(一个单例bean和另一个需要相互引用的bean)情况下,使用@EJB可以工作?(参考以下我的答案 - 我不确定通过切换到@EJB是否正确) - necromancer
2
因为你注入的不是实现,而是在实现上进行干预的代理。因此,你可以获得“延迟绑定”和其他容器特性的优势。 - him

38

@Inject 可以注入任何bean,而 @EJB 只能注入EJBs。您可以使用两者中的任何一个来注入EJBs,但我更喜欢在所有地方都使用 @Inject


3
当我们使用 @Inject 注解时,是什么使得依赖注入生效?是 JavaEE 容器吗?它能注入 POJO 吗? - Koray Tugay
4
使用CDI,它是包含在JavaEE容器中的CDI容器。 - Bozho

16
更新: 此答案可能不正确或已过时。请查看评论获取详情。
我从 @Inject 切换到 @EJB,因为 @EJB 允许循环依赖性注入,而 @Inject 则会出错。
详情:我需要使用 @PostConstruct 调用一个 @Asynchronous 方法,但它会同步执行。唯一的方法是让原始调用另一个bean的方法,并使其回调原始bean的方法。 为此,每个bean都需要对另一个bean进行引用--因此是循环依赖性。@Inject 在此任务上失败,而@EJB 成功了。

@MartijnBurger 我手头没有代码,也没有Java EE环境。只需创建2个Java类并将它们@Inject到彼此的公共字段中。如果这样可以工作,那么我的答案是错误的。如果不能工作,则我的答案到目前为止是正确的。接下来将@Inject更改为@EJB(可能还要注释类本身?我忘了)。然后循环相互注入应该可以正常工作。这就是为什么我从@Inject切换到@EJB的原因。希望这讲得通。 - necromancer
我创建了两个POJO,并将它们注入到彼此中。在我的配置中(WildFly 8.2 = CDI 1.2),可以无问题地工作。 - Martijn Burger
1
谢谢@MartijnBurger,我会确认一下,并在此期间向我的回答添加一个注意事项。 - necromancer
不确定您想要实现什么,但这可能正是您想要的,而且没有循环依赖。http://tomee.apache.org/examples-trunk/async-postconstruct/README.html。此外,异步CDI事件可能是更清晰的方法(取决于要求)。 - JanM

12

这里有一个关于该主题的很好的讨论。Gavin King推荐在非远程EJB中使用@Inject而不是@EJB。

http://www.seamframework.org/107780.lace

或者

https://web.archive.org/web/20140812065624/http://www.seamframework.org/107780.lace

关于使用@EJB或@Inject注入:

  1. 2009年11月,美国/纽约时间20:48 | 链接 Gavin King

那个错误非常奇怪,因为EJB本地引用应该总是可序列化的。也许是glassfish的错误?

基本上,@Inject总是更好的选择,因为:

it is more typesafe,
it supports @Alternatives, and
it is aware of the scope of the injected object.

对于除了声明远程EJB引用之外,我建议不要使用@EJB。

此外,对于远程EJB,我们无法在bean类上声明限定符、@Alternative等元数据,因为客户端简单地无法访问该元数据。此外,还必须指定一些附加元数据,这是我们在本地情况下不需要的(全局JNDI名称等)。因此,所有这些东西都需要放在其他地方:即@Produces声明中。


1
虽然这理论上回答了问题,但最好包括答案的关键部分并提供链接以供参考。这样即使链接失效,这个答案仍然有价值。 - Mifeet
1
https://web.archive.org/web/20140812065624/http://www.seamframework.org/107780.lace - John Manko

5

当使用@EJB和@Inject时,了解会话Bean标识的差异也可能很有用。根据规范,以下代码将始终为true

@EJB Cart cart1;
@EJB Cart cart2;
… if (cart1.equals(cart2)) { // this test must return true ...}

使用@Inject而不是@EJB并不相同。

更多信息请参见无状态会话bean身份


0

在Java EE 5中,@Resource、@PersistentUnit或@EJB注释已经存在注入功能。 但是它仅限于某些资源(数据源、EJB等)和某些组件(Servlets、EJBs、JSF后端bean等)。 使用CDI,您可以通过@Inject注释在任何地方注入几乎任何内容。


0

当您严重依赖于@EJB的属性,如beanName、lookup或beanInterface时,为了使用@Inject,您需要定义一个@Producer字段或方法。


0

@Inject是一个有文档记录的注解,因此IDEA知道如何处理它,您可以在代码中看到不同的颜色。@EJB则没有。


-1

使用 EJB 的 @EBJ 。这是为了创建一个独立于接口类型(分层应用程序)的分离的业务逻辑层。

正确使用可以使业务逻辑在不影响可用性的情况下单独修改和部署,而无需考虑(多个)用户界面应用程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接