Использование 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
.