java - ejemplo - ejb singleton load on startup
Diferencia entre javax.inject.Singleton y javax.ejb.Singleton (3)
Estoy poco confundido. ¿Cuál es la diferencia exacta entre javax.inject.Singleton
y javax.ejb.Singleton
?
He encontrado una explicación plausible here :
De forma predeterminada, los beans de sesión
javax.ejb.Singleton
son transaccionales (sección 13.3.7 de la especificación EJB 3.1) y requieren la adquisición de un bloqueo exclusivo para cada invocación de método empresarial (secciones 4.8.5.4 y 4.8.5.5).En contraste, un
javax.inject.Singleton
no es transaccional y no admite la concurrencia administrada por contenedor (la consecuencia principal es que el contenedor no implementa ningún esquema de bloqueo). [...]Si no necesita las funciones EJB,
@ApplicationScoped
con@ApplicationScoped
(javax.inject.Singleton
no está definido por CDI y, por lo tanto, su semántica no está regida por esa especificación).
Para reducir futuras confusiones, uso esta prueba de unidad pequeña (el nombre del paquete de primer nivel debe reemplazarse):
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);
}
}
Una buena explicación de los conceptos detrás se da en este Article por Adam Bien.
Ya que la respuesta aceptada no resolvió mi problema, publico mi propia respuesta. No será tan bueno como el artículo de Adam Bien, pero definitivamente será más práctico:
Considere el siguiente código:
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");
}
}
Y este servicio 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();
}
}
Usar javax.ejb.Singleton
este código funciona bien. La instancia de DatabaseConnection
se crea una vez y se inyecta al servicio REST. Sin embargo, al reemplazar ejb
en importación con inject
, recibiría NPE en la clase ChampionsAPI al acceder al campo db. .