在 CDI 中有@ApplicationScoped
和 ( javax.inject
)@Singleton
伪作用域。它们之间有什么区别?@ApplicationScoped
除了被代理的事实,而@Singleton
不是被代理的事实。
我可以把我的@Singleton
豆子换成@ApplicationScoped
吗?@ApplicationScoped
bean 可以有两个(或更多)实例吗?
@Singleton
不是 CDI 规范的一部分。它是 EJB 和javax.inject
(JSR-330) 的一部分。规范中没有提到它的行为是什么,因此您只能依赖 Weld 文档中所写的内容。
简而言之:您甚至可以混合使用 (@Singleton
和@ApplicationScoped
),这在某些情况下是有意义的。
(并且在我的工作中按预期工作!)
除了到目前为止的其他答案之外,我还想在现实世界场景中添加更多点来澄清。
对我来说,这个问题源于如何强制应用程序范围的 bean 在应用程序启动时实例化? 在一些讨论中,我陈述了这一点,但到目前为止找不到反对它的有效论据:
在许多现实生活场景/设置中,我会说很难肯定地说 - 从抽象/建模的角度来看 - 某物是(或将成为/被视为)EJB 还是应用程序范围的托管 bean。
(有争议但非结论性的)论据(从我的角度来看)到目前为止反对它:(@BalusC 和所有其他人:我希望看到它们是决定性的,但如果不是,上述可能成立,但论点可能仍然可以帮助读者了解差异/优势/劣势/不良/良好做法)
BalusC:这是一个 EJB 而不是托管 bean,这是完全不同的。EJB 在后端运行,在前端托管 bean。EJB 也在事务上下文中运行。[...] 您只是将企业 bean 与托管 bean 混淆了,我只是指出了这一点。
但:
我:我认为您不太正确并且夸大了含义/用法,这在我看来值得商榷。http://en.wikipedia.org/wiki/Enterprise_JavaBeans
Enterprise JavaBeans (EJB) 是一种用于模块化构建企业软件的托管服务器软件,也是几个 Java API 之一。EJB 是一个服务器端软件组件,它封装了应用程序的业务逻辑。
Enterprise Bean 的类型
会话 Bean [3] 可以是“有状态”、“无状态”或“单例”[...]
消息驱动的 Bean [...]
...在我的情况下仍然适用。
BalusC:单例 EJB 与应用程序范围的 bean 不同。单例 EJB 是读/写锁定的,因此对于您想到的任务可能效率低下/过度复杂。长话短说:拿一本好的 Java EE 书,学习使用正确的工具来完成这项工作。一种方式肯定不是另一种方式。它有效并不意味着它是正确的工具。大锤能够固定螺钉,但它不一定是正确的工具:)
但:
(我在这里看不到大锤 - 抱歉......)很高兴知道锁定默认值(我不知道),但这似乎又不正确:Oracle Java EE 6 Tutorial on Management Concurrent Access in a单例会话 Bean
在创建单例会话 bean 时,可以通过两种方式控制对单例的业务方法的并发访问:容器管理的并发和 bean 管理的并发。[...]
虽然默认情况下,单例使用容器管理的并发,但可以在单例的类级别添加@ConcurrencyManagement(CONTAINER) 注解,以显式设置并发管理类型
通常,当您只想拥有某个对象的一个实例时,您可能应该使用@ApplicationScoped
注释 - 这样的对象是代理的,因此甚至可以开箱即用地正确序列化。
另一方面,也有很多情况,你只想要一个类的实例,但这样的类不能被代理(例如,因为是最终的)——那@Singleton
就是一种救援。因为Singleton
是一个伪作用域,并且不像任何“正常”作用域那样被代理。
@Singleton
在 JSR-299 中指的是单例会话 bean ( javax.ejb.Singleton
, not javax.inject.Singleton
),而不是称为 Singleton 的内置范围内的 JSR-299 托管 bean。
您可能会在您的服务器中发现@ApplicationScoped
每个 EAR 或一个 WAR/EJB-JAR,因为规范中并不清楚,但您绝对不应该期望它是每个 JVM 一个。
还有一个区别:
@Singleton
不是bean定义注释,因为Singleton
范围不是正常范围。然后@ApplicationScoped
是bean定义注释。
使用 CDI 1.1 规范:当发现模式中的应用程序 = 带注释时,Weld 不会识别带有或未@Singleton
加载此的 bean
您可以使用默认构造函数编写类的主要区别之一是在使用时具有私有访问修饰符javax.inject.Singleton
,但是您的类在使用时应该具有至少具有默认访问修饰符的默认构造函数,javax.enterprise.context.ApplicationScoped
这是JBOSS 6.1 GA Final
实现
我知道这是一篇旧帖子,但这是我经常被问到的一个问题。
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。)