CDI中的@ApplicationScoped和@Singleton范围有什么区别?

时间:2010-12-29 16:28:06

标签: java scope cdi

在CDI中,有@ApplicationScoped和(javax.inject@Singleton伪范围。他们之间有什么区别?除了代理@ApplicationScoped,而@Singleton不代理的事实。

我可以将@Singleton bean更改为@ApplicationScoped吗? @ApplicationScoped bean可以有两个(或更多)实例吗?

7 个答案:

答案 0 :(得分:23)

@Singleton不是CDI规范的一部分。它是EJB和javax.inject(JSR-330)的一部分。规范中没有提到它的行为是什么,所以你只能依赖于Weld文档中的内容。

答案 1 :(得分:15)

简而言之:您甚至可以将其混合(@Singleton@ApplicationScoped),这在某些情况下也很有意义。 (并在我的预期工作!)

除了到目前为止的其他答案,我还想在实际场景中添加更多要点以澄清。

对我来说,这个问题是从How do I force an application-scoped bean to instantiate at application startup?开发出来的 在一些讨论中我说了这个,到目前为止找不到有效的论据:

  

在很多现实场景/设置中,我会说它很难   绝对可以说 - 从抽象/建模的角度来看 - 是否   某些东西(或将被视为/将被视为)EJB或应用程序范围的托管bean。

到目前为止(从我的观点来看)(有争议的但不是决定性的)论据反对它: (@BalusC和所有其他人:我希望看到它们具有决定性,但如果没有,上述情况可能仍然适用,然而这些争论可能仍然有助于读者获得差异/优势/劣势/糟糕/良好做法)

EJB与Managed Bean

  

BalusC :这是一个EJB而不是托管bean,这是完全不同的。 EJB在前端运行,在前端运行托管bean。 EJB也在事务上下文中运行。    [...]您刚刚将企业bean与托管bean混为一谈,我只是指出了这一点。

但:

  

me :我认为你不太正确并且夸大其含义/用法,这看起来对我有争议。 http://en.wikipedia.org/wiki/Enterprise_JavaBeans

     

Enterprise JavaBeans(EJB)是一种用于企业软件模块化构建的托管服务器软件,也是多种Java API之一。 EJB是一个服务器端软件组件,它封装了应用程序的业务逻辑。

     

企业Bean的类型

     

会话豆[3]可以是"有状态","无状态"或" Singleton" [...]

     

消息驱动的豆[...]

......在我的案例中仍然适用。

Singleton EJB与Application Scoped Bean

锁定

  

BalusC :单例EJB与应用程序作用域bean不同。单例EJB是读/写锁定的,因此对于您考虑的任务可能效率低/过度卷积。简而言之:获取一本优秀的Java EE书籍并学习如何使用正确的工具。一种方式绝对不是另一种方式。它起作用并不意味着它是正确的工具。大锤能够固定螺钉,但它不一定是正确的工具:)

但:

(我在这里看不到大锤 - 对不起......) 知道锁定默认值很好(我没有意识到),但这似乎再次不正确:Oracle Java EE 6 Tutorial on Managing Concurrent Access in a Singleton Session Bean

  

创建单例会话bean时,可以通过两种方式控制对单例业务方法的并发访问:容器管理的并发和bean管理的并发。   [...]

     

虽然默认情况下,单例使用容器管理的并发,但可以在单例的类级别添加@ConcurrencyManagement(CONTAINER)注释以显式设置并发管理类型

答案 2 :(得分:9)

JSR-299中的

@Singleton引用Singleton会话bean(javax.ejb.Singleton,而不是javax.inject.Singleton),而不是名为Singleton的内置作用域中的JSR-299托管bean。

您可能会在服务器中发现@ApplicationScoped是每个EAR一个或每个WAR / EJB-JAR一个,因为规范中不清楚,但您绝对不应期望它是每个JVM一个

答案 3 :(得分:8)

通常当你想只有一个对象的一个​​实例时,你可能应该使用@ApplicationScoped注释 - 这样的对象被代理,因此甚至可以开箱即用地进行正确的序列化。

另一方面,也有很多情况,你只需要一个类的一个实例,但这样的类不能被代理(例如因为是最终的) - 然后@Singleton是一个救援。因为Singleton是伪范围,并且没有像任何"普通"那样被代理。范围。

答案 4 :(得分:4)

还有一个区别: @Singleton不是bean定义注释,因为Singleton范围不是正常范围。 然后@ApplicationScoped是定义注释的bean。

使用CDI 1.1规范:当发现模式中的应用程序=注释时,Weld不识别具有@Singleton且未加载此

的bean

答案 5 :(得分:2)

使用javax.inject.Singleton时,您可以使用默认承包商编写班级的主要差异之一是私有访问修饰符,但是在使用javax.enterprise.context.ApplicationScoped时,您的班级应该具有至少默认访问修饰符的默认承包商这是JBOSS 6.1 GA Final实施

答案 6 :(得分:0)

我知道这是一篇旧帖子,但我经常被问到这个问题。

恕我直言,转到源 -> https://www.javadoc.io/doc/jakarta.enterprise/jakarta.enterprise.cdi-api/latest/jakarta/enterprise/context/ApplicationScoped.html

https://www.javadoc.io/doc/jakarta.inject/jakarta.inject-api/latest/jakarta/inject/Singleton.html

https://quarkus.io/guides/cdi-reference#lazy_by_default 提供了一个很好的参考,在实际使用方面比较了两者。

(还需要注意的是,在最后一种情况下,Quarkus 为您创建了无参数构造函数以满足 CDI bean 的要求,因此您不需要 DIY 或 Lombok-it。)