Ответы:
потому что, когда вызывается конструктор, бин еще не инициализирован, т.е. не вводятся зависимости. В @PostConstruct
методе компонент полностью инициализирован, и вы можете использовать зависимости.
потому что это контракт, который гарантирует, что этот метод будет вызываться только один раз в жизненном цикле компонента. Может случиться (хотя и маловероятно), что контейнер во время своей внутренней работы несколько раз создается экземпляром контейнера, но это гарантирует, что @PostConstruct
он будет вызван только один раз.
Основная проблема заключается в том , что:
в конструкторе внедрение зависимостей еще не произошло *
* очевидно, исключая конструктор инъекций
Пример из реальной жизни:
public class Foo {
@Inject
Logger LOG;
@PostConstruct
public void fooInit(){
LOG.info("This will be printed; LOG has already been injected");
}
public Foo() {
LOG.info("This will NOT be printed, LOG is still null");
// NullPointerException will be thrown here
}
}
ВАЖНО :
@PostConstruct
и @PreDestroy
были полностью удалены в Java 11 .
Чтобы продолжать использовать их, вам нужно добавить JAR-файл javax.annotation-api в ваши зависимости.
<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
in a constructor, the injection of the dependencies has not yet occurred.
true с установщиком или внедрением поля, но не верно с внедрением конструктора.
Если ваш класс выполняет всю свою инициализацию в конструкторе, то @PostConstruct
он действительно избыточен.
Однако, если ваш класс имеет свои зависимости, введенные с использованием методов установки, тогда конструктор класса не может полностью инициализировать объект, и иногда некоторая инициализация должна выполняться после того, как все методы установки были вызваны, отсюда и пример использования @PostConstruct
.
Рассмотрим следующий сценарий:
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Так как Car должен быть создан перед внедрением поля, механизм точки инжекции все еще равен нулю во время выполнения конструктора, что приводит к исключению NullPointerException.
Эта проблема может быть решена либо с помощью внедрения зависимостей JSR-330 для внедрения в конструктор Java, либо с помощью общих аннотаций JSR 250 для аннотации метода Java @PostConstruct.
@PostConstruct
JSR-250 определяет общий набор аннотаций, который был включен в Java SE 6.
Аннотация PostConstruct используется для метода, который необходимо выполнить после внедрения зависимости для выполнения любой инициализации. Этот метод ДОЛЖЕН быть вызван до того, как класс введен в эксплуатацию. Эта аннотация ДОЛЖНА поддерживаться всеми классами, которые поддерживают внедрение зависимостей.
JSR-250 гл. 2.5 javax.annotation.PostConstruct
Аннотация @PostConstruct позволяет определять методы, которые должны быть выполнены после того, как экземпляр был создан и все инъекции были выполнены.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
Вместо выполнения инициализации в конструкторе код перемещается в метод, аннотированный @PostConstruct.
Обработка методов после конструирования - это простой вопрос поиска всех методов, аннотированных @PostConstruct, и последующего их вызова.
private void processPostConstruct(Class type, T targetInstance) {
Method[] declaredMethods = type.getDeclaredMethods();
Arrays.stream(declaredMethods)
.filter(method -> method.getAnnotation(PostConstruct.class) != null)
.forEach(postConstructMethod -> {
try {
postConstructMethod.setAccessible(true);
postConstructMethod.invoke(targetInstance, new Object[]{});
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
throw new RuntimeException(ex);
}
});
}
Обработка методов после конструирования должна выполняться после того, как реализация и внедрение были завершены.
final
. Учитывая этот шаблон, почему@PostConstruct
он добавляется в J2EE - они наверняка видели другой вариант использования?