web-dev-qa-db-fra.com

Différence entre javax.inject.Singleton et javax.ejb.Singleton

je suis un peu confus. Quelle est la différence exacte entre javax.inject.Singleton et javax.ejb.Singleton

22
Hakan Kiyar

J'ai trouvé une explication plausible ici :

Par défaut, les beans session javax.ejb.Singleton sont transactionnels (section 13.3.7 de la spécification EJB 3.1) et nécessitent l'acquisition d'un verrou exclusif pour chaque appel de méthode métier (sections 4.8.5.4 et 4.8.5.5).

En revanche, un javax.inject.Singleton n'est pas transactionnel et ne prend pas en charge la simultanéité gérée par le conteneur (la conséquence majeure étant qu'aucun schéma de verrouillage n'est implémenté par le conteneur). [...]

Si vous n'avez pas besoin des fonctionnalités EJB, restez sur @ApplicationScoped (javax.inject.Singleton n'est pas défini par CDI et sa sémantique n'est donc pas régie par cette spécification).

Pour éviter toute confusion, j'utilise ce petit test unitaire (le nom du paquet de premier niveau doit être remplacé): 

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

Comme la réponse acceptée ne résout pas mon problème, je poste ma propre réponse. Ce ne sera pas aussi bon qu'un article d'Adam Bien mais sera certainement plus pratique:

Considérons le code suivant:

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");
    }

}

Et ce service 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();
    }
}

En utilisant javax.ejb.Singleton, ce code fonctionne très bien. L’instance DatabaseConnection est créée une fois et injectée dans le service REST . Toutefois, si vous remplacez ejb dans l’importation par inject, vous recevrez un NPE dans la classe ChampionsAPI lors de l’accès au champ db - c’est que votre Singleton n’a pas été créé (pour une raison quelconque). , peut-être parce qu’il faut utiliser des interfaces en utilisant javax.inject.Singleton?).

0
kukis