javax.inject.Singleton 和 javax.ejb.Singleton 的区别

Posted

技术标签:

【中文标题】javax.inject.Singleton 和 javax.ejb.Singleton 的区别【英文标题】:Difference between javax.inject.Singleton and javax.ejb.Singleton 【发布时间】:2016-08-02 18:36:02 【问题描述】:

我有点困惑。 javax.inject.Singletonjavax.ejb.Singleton 之间的确切区别是什么?

【问题讨论】:

【参考方案1】:

我找到了一个合理的解释here:

默认情况下,javax.ejb.Singleton 会话 bean 是事务性的(EJB 3.1 规范的第 13.3.7 节)并且需要为每个业务方法调用获取排他锁(第 4.8.5.4 和 4.8.5.5 节)。

相比之下,javax.inject.Singleton 不是事务性的,也不支持容器管理的并发(主要后果是容器没有实现锁定方案)。 [...]

如果您不需要 EJB 功能,请坚持使用 @ApplicationScopedjavax.inject.Singleton 未由 CDI 定义,因此其语义不受该规范的约束)。

为了减少将来的混乱,我使用了这个小单元测试(需要替换第一级包名):

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;

import org.junit.Test;

public class SingletonTest 

    /** requires com.tngtech.archunit:archunit-junit:0.4.0 */
    @Test
    public void detectWrongSingletonAnnotation() 

        final ClassFileImporter importer = new ClassFileImporter();
        final JavaClasses classes = importer.importPackages("first_level_package");

        noClasses().should().beAnnotatedWith("javax.inject.Singleton")
                .as("Please use javax.ejb.Singleton instead of javax.inject.Singleton.")
                .check(classes);
    

【讨论】:

【参考方案2】:

由于接受的答案没有解决我的问题,我发布了我自己的答案。它不会像 Adam Bien 的文章那么好,但肯定会更实用:

考虑以下代码:

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;

@Singleton
public class DatabaseConnection 

    @PostConstruct
    public void init() 
        System.out.println("init");
    

    public ChampionComp getFirstRecord() 
        return new ChampionComp("Ashe", "Teemo", "Warwick", 
                "Blitzcrank", "Syndra", "Anivia", "Brand", "Rammus", "Xin Zhao", "Irelia");
    


还有这个 REST 服务:

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.Path;

@Path("/champions")
public class ChampionsAPI 

    @Inject
    private DatabaseConnection db;

    @GET
    @Produces("text/plain")
    public String getClichedMessage() 
        ChampionComp comp = db.getFirstRecord();
        return comp.toString();
    

使用javax.ejb.Singleton 这段代码可以正常工作。 DatabaseConnection 实例创建一次并注入 REST 服务。 但是,当用inject 替换导入中的ejb 时,您将在访问db 字段时在ChampionsAPI 类中收到NPE - 那是因为您的Singleton 没有创建(由于某种原因,可能是因为在使用javax.inject.Singleton 时需要使用接口?)。

【讨论】:

这不是单例包的问题,​​而是 CDI 发现问题。在您的情况下,CDI 没有“激活”。如果 CDI 被正确激活(使用 beans.xml 等),注入将正常工作。【参考方案3】:

简单明了:

javax.ejb.Singleton 是一个用于创建@Singleton EJB 的注解(相对于@Sateless EJB 或@Stateful EJB)

另一方面,javax.inject.Singleton 是用于创建具有单例范围的 CDI 的注解

所以基本上,一个创建单例 EJB,而另一个创建具有单例范围的 CDI

【讨论】:

以上是关于javax.inject.Singleton 和 javax.ejb.Singleton 的区别的主要内容,如果未能解决你的问题,请参考以下文章

Scala play框架中@Singleton的使用

& 和 && 区别和联系,| 和 || 区别和联系

第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等

shell中$()和 ` `${}${!}${#}$[] 和$(()),[ ] 和(( ))和 [[ ]]

Java基础8---面向对象代码块和继承和this和super和重写和重载和final

Java基础8---面向对象代码块和继承和this和super和重写和重载和final