CDI 中的@ApplicationScoped 和@Singleton 作用域有啥区别?

Posted

技术标签:

【中文标题】CDI 中的@ApplicationScoped 和@Singleton 作用域有啥区别?【英文标题】:What is the difference between @ApplicationScoped and @Singleton scopes in CDI?CDI 中的@ApplicationScoped 和@Singleton 作用域有什么区别? 【发布时间】:2011-06-01 03:33:32 【问题描述】:

在 CDI 中有 @ApplicationScoped 和 (javax.inject) @Singleton 伪范围。它们之间有什么区别?除了@ApplicationScoped 被代理,@Singleton 没有被代理。

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

【问题讨论】:

你读过Weld reference吗?在第 5.4 节(第 36 页)中有一些关于 @ApplicationScoped@Singleton 之间实际差异的解释。 您指的是哪个单例范围 - javax.ejb 或 javax.inject? 【参考方案1】:

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

【讨论】:

这不是真的。有注解 javax.inject.Singleton。它是 CDI 的一部分。在这里查看:docs.jboss.org/weld/reference/1.0.1-Final/en-US/html_single/… @amorphis - 我面前有 CDI 规范。我什至已经实现了它的一部分,它没有提到任何关于@Singleton 的内容。它仅在一个示例中显示,没有说明。 CDI 确实依赖于javax.inject,但严格来说它不是 CDI 规范的一部分。也就是说,我更正了我的答案。【参考方案2】:

简而言之:您甚至可以混合使用(@Singleton@ApplicationScoped),这在某些情况下是有意义的。 (并且在我的工作中按预期工作!)

除了到目前为止的其他答案之外,我还想在现实世界的场景中添加更多点来澄清。

对我来说,这个问题源于How do I force an application-scoped bean to instantiate at application startup? 在那里的一些讨论中,我陈述了这一点,但到目前为止找不到反对它的有效论据:

在很多现实生活场景/设置中,我会说这 很难 肯定地说 - 从抽象/建模的角度来看 - 是否 某物是(或将成为/被视为)EJB 或应用程序范围的托管 bean。

(有争议但不是结论性的)论点(从我的角度来看)到目前为止反对它: (@BalusC 和所有其他人:我希望看到他们得出结论,但如果不是,上述内容可能是正确的,但这些论点仍然可以帮助读者了解差异/优势/劣势/坏/好的做法)

EJB 与托管 Bean

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

但是:

:我认为你不太正确并且夸大了含义/用法,这在我看来值得商榷。 http://en.wikipedia.org/wiki/Enterprise_JavaBeans

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

企业 Bean 的类型

可以是“有状态”、“无状态”或“单例”的会话 Bean [3] [...]

消息驱动的 Bean [...]

...在我的情况下仍然适用。

单例 EJB 与应用范围 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)注解来显式设置并发管理类型

【讨论】:

Weld 不喜欢混合:加载应用程序时出现异常:CDI 定义失败:WELD-000046:在 [EnhancedAnnotatedTypeImpl] public ApplicationScoped Singleton MyClass 上最多可以指定一个范围。使用 javax.inject.Singleton。【参考方案3】:

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

另一方面,也有很多情况,你只想要一个类的实例,但这样的类不能被代理(例如,因为是最终的) - 那么@Singleton 是一种救援。因为Singleton 是一个伪作用域,不像任何“正常”作用域那样被代理。

【讨论】:

我对此表示反对,因为它非常不清楚。我已经在 J​​ava EE 中编码五年,学习教程和阅读书籍,但我不明白你所说的“这样的对象被代理”、“甚至可以正确序列化”和“伪-范围”。我很想知道这是什么意思,因为听起来你知道你在说什么,但正如它所写的那样,我无法想象你的回答会帮助大多数 Java EE 开发人员。 也就是说,我知道 EJB 是代理的。我的困惑部分在于您对单身人士所做的区分。 @DavidS:我同意答案可能更具体,参考资料可以提供帮助。但我认为他的回答是有效的。我正在使用使用 CDI 2.0 的 Weld 3,从文档中您可以看到 Demecki 关于范围和代理的说法。 5.4. The singleton pseudo-scope "这个伪作用域有点问题。作用域@Singleton的bean没有代理对象。客户端持有对单例实例的直接引用。所以我们需要考虑客户端的情况可以序列化的"【参考方案4】:

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

您可能会在您的服务器中发现@ApplicationScoped 是一个 EAR 或一个 WAR/EJB-JAR,因为规范中没有明确说明,但您绝对不应该期望它是每个 JVM 一个。

【讨论】:

【参考方案5】:

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

使用 CDI 1.1 规范:当处于发现模式的应用程序 = 带注释时,Weld 不会使用 @Singleton 识别 bean 并且不会加载它

【讨论】:

【参考方案6】:

在使用javax.inject.Singleton 时,您可以使用默认构造函数编写类的主要区别之一是私有访问修饰符,但是在使用javax.enterprise.context.ApplicationScoped 时,您的类应该具有至少具有默认访问修饰符的默认构造函数,这是@987654323 @实现

【讨论】:

你的意思是“默认构造函数”吗?【参考方案7】:

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

恕我直言,去源头-> 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。)

【讨论】:

“链接列表”不鼓励作为答案 - 并不是说​​您不能包含链接,而是您应该在答案中包含您自己的解释(可能利用这些链接中的信息)。 罗杰。对于那个很抱歉。记下更新。 欣赏这些链接。有时,很难弄清楚从哪里开始或找到合适的资源来回答问题

以上是关于CDI 中的@ApplicationScoped 和@Singleton 作用域有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

JavaEE6 DAO:应该是@Stateless 还是@ApplicationScoped?

多次构造 Eager ApplicationScoped 托管 bean

@ApplicationScoped JSF 托管 bean 的并发性

JEE6 @ApplicationScoped bean 和并发

区别:@SessionScoped vs @Stateful 和 @ApplicationScoped vs @Singleton [关闭]

请解释CDI中的@Produces注解