我有点困惑。 javax.inject.Singleton
和 javax.ejb.Singleton
之间的确切区别是什么?
我在这里找到了一个合理的解释:
默认情况下,
javax.ejb.Singleton
会话Bean是事务性的(EJB 3.1规范第13.3.7节),并且每个业务方法调用都需要获取独占锁(第4.8.5.4和4.8.5.5节)。相比之下,
javax.inject.Singleton
不是事务性的,也不支持容器管理的并发(主要的结果是容器不实现任何锁定方案)。[...]如果您不需要EJB功能,请使用
@ApplicationScoped
(javax.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);
}
}
由于接受的答案未能解决我的问题,我发布了自己的答案。这篇文章可能没有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");
}
}
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
时需要利用接口?)。