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

36

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

3个回答

20

我在这里找到了一个合理的解释:

默认情况下,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);
    }
}

0
简单明了地说:
javax.ejb.Singleton 是用于创建 @Singleton EJB(而不是 @Sateless EJB 或 @Stateful EJB)的注释。
另一方面,javax.inject.Singleton 是用于创建具有单例范围的 CDI 的注释。
因此,一个用于创建单例 EJB,而另一个用于创建具有单例范围的 CDI。

0

由于接受的答案未能解决我的问题,我发布了自己的答案。这篇文章可能没有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服务中。 但是,当将导入的ejb替换为inject时,访问db字段会在ChampionsAPI类中收到NPE错误-这是因为您的Singleton没有被创建(可能是因为在使用javax.inject.Singleton时需要利用接口?)。


7
这不是Singleton包的问题,而是CDI发现问题。在你的情况下,CDI没有被“激活”。如果CDI被正确地激活(使用beans.xml等),注入将正常工作。 - Rouliboy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接