Разница между javax.впрыскивать.Синглтон и javax.EJB-компонента.Одиночка
Я немного запутался. Какова точная разница между javax.inject.Singleton
и javax.ejb.Singleton
?
3 ответов
хорошее объяснение понятий, стоящих за этим, дано в этом статьи Адам Бьен.
я нашел правдоподобное объяснение здесь:
по умолчанию
javax.ejb.Singleton
сеансовые компоненты являются транзакционными (раздел 13.3.7 спецификации EJB 3.1) и требуют приобретения исключительной блокировки для каждого вызова бизнес-метода (разделы 4.8.5.4 и 4.8.5.5).напротив, a
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);
}
}
поскольку принятый ответ не решил мою проблему, я отправлю свой собственный ответ. Это будет не так хорошо, как статья Адама Бьена, но определенно будет более практичным:
рассмотрим следующий код:
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
этот код работает просто отлично. The DatabaseConnection
экземпляр создается один раз и вводится в службу REST.
Однако при замене ejb
в импорт с inject
вы получите NPE в ChampionsAPI класса а доступ к полю БД-это потому, что ваш Синглтон не был создан (по какой-то причине, возможно, потому, что нужно использовать интерфейсы при использовании javax.inject.Singleton
? ).