【问题标题】:What's the point of using @Scoped with EJBs?将 @Scoped 与 EJB 一起使用有什么意义?
【发布时间】:2011-08-26 11:51:32
【问题描述】:

通常我使用@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 的回答下查看我的评论。

【问题讨论】:

    标签: java jakarta-ee ejb-3.0


    【解决方案1】:

    @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 规范负责人)建议始终使用@Inject 而不是@EJB。唯一的例外涉及远程 EJB,其中仍使用 @EJB。

    关于 EJB 和 CDI 的部分混淆在于 CDI 是 Java EE 中的一种新组件模型,并且仍然相对较新。尽管它们彼此集成得相当好,但它们仍然是两种不同的组件模型,并且尚未考虑所有最佳实践。 Reza Rahman(EG 成员、EJB 书籍作者和 CDI 实现 CanDI 的作者)建议将来可能将 EJB 模型改进为一组 CDI 服务。实际上,在 Java EE 7 中,通过将事务服务与 EJB 分离并通过 (CDI) 注释使它们可用,正在迈出一步。

    【讨论】:

    • 我不太明白。 CDI 使用@Scoped 注释来决定注入哪个实例(之前使用的实例或新实例)。当我们使用@EJB 时,我认为注入了某种代理对象。当我们调用该代理对象的方法时,它会从池中调用可用对象的方法——如果它是无状态的。如果它是有状态的,这样的代理可以确保我们总是在处理之前在这个注入点注入的同一个对象。这样的范围可以理解为“注入点范围”IMO。 @Scoped 注解在这里如何应用?
    • 如果 bean 是有状态的,则确实使用范围注释来选择要注入的 stub-that-points-to-an-instance。如果没有范围,每次都会获得一个有状态 bean 的新存根,这有点违背有状态 bean 的目的。使用范围的替代方法是从 JNDI 请求有状态 bean 并将其分配给托管 bean 的实例变量,将其存储在 HTTP 会话中,等等。
    • 这是否意味着如果我在(例如)请求范围的 faces bean 中注入了 ejb 并且这样的 ejb 也被注释了 @SessionScoped,那么同一实例将在一个会话中注入到所有 faces bean? (如果我使用@Inject 注入它就会这样)
    • 我刚刚检查了我的项目,但它并没有像那样工作。我使用了@ApplicationScoped,所以应该将一个ejb 实例放到bean 的所有实例中。然而,它不是,而是如果使用了@Inject。据我了解,我应该有兼容的范围 相同的注入点。对吗?
    • @EJB 是 EJB 特定的注入注解。我认为它不会考虑范围,但我也必须对此进行测试。
    猜你喜欢
    • 2013-09-06
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多