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
是一个伪作用域,不像任何“正常”作用域那样被代理。
【讨论】:
我对此表示反对,因为它非常不清楚。我已经在 Java 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 [关闭]