Разница между 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 ? ).