通常我使用@RequestScoped
或@SessionScoped
(来自javax.enterprise.context
)使用@Inject
注入对象(例如在faces bean中)。
我也在使用EJB。据我所知,一组无状态EJB副本(池)用于注入对象。存在多个副本的原因是确保不会同时访问EJB的一个实例。在谈到有状态EJB时(同样如我所理解的),这样的一个实例必然会被注入具体的注入点。并且使用@EJB
(无状态的)注入它们。
我经常可以在网上看到将@Stateless
或@Stateful
与@Scoped
结合使用的示例。这是什么意思?
修改(试图澄清,因为没有人回复此时刻):
我特别感兴趣的是这样的范围注释是否会随时改变(以及它们是如何)创建EJB实例的时刻。
根据我的理解:如果我有@EJB
注释字段,则在那里注入适当类的对象。如果这样的EJB是无状态的,容器只需从预先创建的实例池中获取自由实例。如有必要,可以调整池的大小。它是无状态的,因为不保证在我们的类的方法调用(即具有包含EJB引用的字段的类)之间保留对象。
我们也可以使用有状态EJB,在这种情况下,在方法调用期间会保留一个实例。我认为,每次创建对象时只需注入一次。 (还有单例EJB,它在所有对象之间共享)。
我在这里找不到EJB的@Scoped注释的目的。
编辑2:
如果要通过EJB和DI(通过@Inject
)机制注入类,可以使用这种注释组合。然而,这是特殊情况而不是优雅。我问你是否知道其他原因。
编辑3: 请参阅arjan的回答中的评论。
答案 0 :(得分:8)
可以显式确定@Stateless或@Singleton bean的范围,以防止其范围自动修改为可能非法的范围。例如。这两种bean类型都不允许是@RequestScoped。有关详细信息,请参阅此链接:http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html/CDI.html
@Stateful很有意义(明确地)作用域。也就是说,如果没有作为程序员的范围,您必须注意调用@Remove带注释的方法。这可能很麻烦,因为这样的bean通常不会在一个方法中使用,你可以在finally块中调用@Remove方法。使用作用域,当作用域结束时,将完全删除bean。
此外,如果没有作用域,则无法始终使用注入来获取对有状态bean的存根的引用。也就是说,每次注入发生时,您都会获得一个新实例。在请求作用域(JSF)支持bean中注入有状态bean时,这尤其麻烦,您可以在几个请求中保留有状态bean。
然后,结合@Named,您还可以直接使用会话bean作为支持bean来展平您的应用程序层(参见例如http://jaxenter.com/java-ee-6-overview-35987-2.html)。显然,在这种情况下你需要一个明确的范围。现在,在较大的应用程序中展平图层可能不是最佳实践,但对于较小的应用程序和/或刚刚开始使用Java EE的人来说,肯定希望将业务逻辑直接放入支持bean。然后要求支持bean可以访问“业务bean”通常具有的相同类型的服务(主要是事务)。
最后,Gavin King(CDI spec lead)建议始终使用@Inject而不是@EJB。唯一的例外是远程EJB,其中仍然使用@EJB。
关于EJB和CDI的部分混淆是CDI是Java EE中的一个新组件模型,但仍然相对较新。虽然它们相互整合得很好,但它们仍然是两种不同的组件模型,并不是所有最佳实践都已经过考虑。 Reza Rahman(EG成员,EJB书籍作者和CDI实现CanDI的作者)建议将来可能将EJB模型改进为一组CDI服务。实际上,在Java EE 7中,通过将事务服务与EJB分离并通过(CDI)注释使它们可用来实现一个步骤。