web-dev-qa-db-de.com

Unterschied zwischen javax.inject.Singleton und javax.ejb.Singleton

ich bin etwas verwirrt. Was ist der genaue Unterschied zwischen javax.inject.Singleton und javax.ejb.Singleton

22
Hakan Kiyar

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);
    }
}
8
Jens Piegsa

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.

0
kukis