ich bin etwas verwirrt. Was ist der genaue Unterschied zwischen javax.inject.Singleton
und javax.ejb.Singleton
?
Ich fand eine plausible Erklärung hier :
Standardmäßig sind
javax.ejb.Singleton
-Session-Beans transaktional (Abschnitt 13.3.7 der EJB 3.1-Spezifikation) und erfordern den Erwerb einer exklusiven Sperre für jeden Aufruf einer Geschäftsmethode (Abschnitte 4.8.5.4 und 4.8.5.5).Im Gegensatz dazu ist ein
javax.inject.Singleton
keine Transaktion und unterstützt keine durch den Container verwaltete Parallelität (die Hauptfolge ist, dass der Container kein Sperrschema implementiert). [...]Wenn Sie keine EJB-Funktionen benötigen, bleiben Sie bei
@ApplicationScoped
(javax.inject.Singleton
wird nicht von CDI definiert, und seine Semantik unterliegt daher nicht dieser Spezifikation).
Um zukünftige Verwirrung zu vermeiden, verwende ich diesen kleinen Komponententest (der erste Name des Pakets muss ersetzt werden):
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);
}
}
Da die akzeptierte Antwort mein Problem nicht gelöst hat, poste ich meine eigene Antwort. Es wird nicht so gut sein wie Artikel von Adam Bien, aber definitiv praktischer:
Betrachten Sie den folgenden Code:
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");
}
}
Und dieser REST Service:
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();
}
}
Mit javax.ejb.Singleton
funktioniert dieser Code gut. Die DatabaseConnection
-Instanz wird einmal erstellt und in den REST -Dienst injiziert. __ Wenn Sie jedoch ejb
im Import durch inject
ersetzen, erhalten Sie NPE in der ChampionsAPI-Klasse, während Sie auf das db-Feld zugreifen , vielleicht, weil man bei der Verwendung von javax.inject.Singleton
? Schnittstellen verwenden muss.