Использование CDI в одноэлементном шаблоне

Я пытаюсь ввести объект logger в класс, который реализуется после одноэлементного подхода.

Код выглядит примерно так:

Logger класс:

public class LoggerFactory {
    @Produces 
    public Logger getLogger(InjectionPoint caller){
        return Logger.getLogger(caller.getMember().getDeclaringClass().getName());
    }
}

Затем я создаю класс, который требует регистратора и реализует шаблон Singleton:

public class MySingleton{
    @Inject
    private Logger logger;

    private MySingleton instance;

    /*
     * Private constructor for singleton implementation
     */
    private MySingleton(){
        logger.info("Creating one and only one instance here!");
    }

    public MySingleton getInstance(){

        if(instance == null) {
            instance = new MySingleton();
        }

        return instance;
    }

}

Если я запускаю код (на Glassfish 3.1.2.2), я получаю NPE, как только я пытаюсь использовать регистратор. Что я делаю неправильно (файл beans.xml на месте)? Я также попытался использовать @Inject с помощью метода setter для объекта Logger, но не повезло.

Ответ 1

Инъекции происходят после построения. Поэтому вы не можете использовать его в конструкторе.

Один из способов - добавить метод annotated @PostConstruct, который может быть вызван после инъекций.

@PostConstruct
public void init() {
    logger.info("Creating one and only one instance here!");
}

На боковой панели я Думайте, что вы неправильно рассматриваете проблему. CDI имеет хорошую поддержку синглтона

создать класс аннотированный @Singleton

@Singleton
public class MySingleton {

    @Inject
    Logger logger;

    @PostConstruct
    public void init() {
        logger.info("Creating one and only one instance here!");
    }

}

Выше предполагается, что вы используете CDI для java ee (JSR-299).

Если вы используете JSR 330 Injection Dependency Injection (guice и т.д.) ссылка

Вы можете использовать инъекцию конструктора:

@Singleton
public class MySingleton {


    private final Logger logger;

    @Inject
    public MySingleton (Logger logger) {
        this.logger = logger;
        logger.info("Creating one and only one instance here!");
    }
}

Ответ 2

Это не сработает, потому что инъекция, как уже упоминалось, будет выполняться после вызова конструктора.

Методы, аннотированные с помощью @PostConstruct, вызываются после завершения инъекции и перед тем, как сам объект будет предоставлен где-то еще.

Однако, инъекция работает, только если экземпляр вашего класса обеспечивается самой инъекцией. Это происходит из-за инъекции в зависимости от проксирования.

Поэтому вам нужно будет вводить свой MySingleton везде, где вам это нужно. Чтобы быть уверенным, что это синглтон, аннотируйте его @Singleton, и контейнер будет работать для вас.

Достаточно будьте осторожны, этот синглтон в терминах спецификации CDI не означает только один экземпляр, а скорее только одно из инициализации @PostConstruct.