Respostas:
porque quando o construtor é chamado, o bean ainda não foi inicializado - ou seja, nenhuma dependência é injetada. No @PostConstruct
método, o bean é totalmente inicializado e você pode usar as dependências.
porque este é o contrato que garante que esse método será chamado apenas uma vez no ciclo de vida do bean. Pode acontecer (embora improvável) que um bean seja instanciado várias vezes pelo contêiner em seu trabalho interno, mas garante que @PostConstruct
será invocado apenas uma vez.
O principal problema é que:
em um construtor, a injeção das dependências ainda não ocorreu *
* obviamente excluindo injeção de construtor
Exemplo do mundo real:
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
}
}
IMPORTANTE :
@PostConstruct
e @PreDestroy
foram completamente removidos no Java 11 .
Para continuar usando-os, você precisará adicionar o JAR javax.annotation-api às suas dependências.
<!-- 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 com injeção de setter ou campo, mas não com injeção de construtor.
Se sua classe executa toda a sua inicialização no construtor, então @PostConstruct
é realmente redundante.
No entanto, se sua classe tiver suas dependências injetadas usando métodos setter, o construtor da classe não poderá inicializar completamente o objeto e, algumas vezes, alguma inicialização precisará ser executada após todos os métodos setter terem sido chamados, daí o caso de uso de @PostConstruct
.
Considere o seguinte cenário:
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Como o carro precisa ser instanciado antes da injeção no campo, o mecanismo do ponto de injeção ainda é nulo durante a execução do construtor, resultando em uma NullPointerException.
Esse problema pode ser resolvido pelo JSR-330 Dependency Injection for Java construtor ou pelo JSR 250 Common Annotations para a anotação do método Java @PostConstruct.
@PostConstruct
O JSR-250 define um conjunto comum de anotações que foi incluído no Java SE 6.
A anotação PostConstruct é usada em um método que precisa ser executado após a injeção de dependência ser executada para executar qualquer inicialização. Este método deve ser invocado antes que a classe seja colocada em serviço. Esta anotação DEVE ser suportada em todas as classes que suportam injeção de dependência.
JSR-250 Chap. 2.5 javax.annotation.PostConstruct
A anotação @PostConstruct permite a definição de métodos a serem executados após a instância ter sido instanciada e todas as injeções terem sido executadas.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
Em vez de executar a inicialização no construtor, o código é movido para um método anotado com @PostConstruct.
O processamento de métodos pós-construção é uma questão simples de encontrar todos os métodos anotados com @PostConstruct e invocá-los por vez.
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);
}
});
}
O processamento dos métodos pós-construção deve ser realizado após a conclusão da instanciação e injeção.
final
. Dado esse padrão, por que está@PostConstruct
sendo adicionado ao J2EE - eles devem ter visto outro caso de uso com certeza?