Respuestas:
porque cuando se llama al constructor, el bean aún no se inicializa, es decir, no se inyectan dependencias. En el @PostConstruct
método, el bean está completamente inicializado y puede usar las dependencias.
porque este es el contrato que garantiza que este método se invocará solo una vez en el ciclo de vida del bean. Puede suceder (aunque es poco probable) que un contenedor se instancia varias veces por el contenedor en su funcionamiento interno, pero garantiza que @PostConstruct
se invocará solo una vez.
El principal problema es que:
en un constructor, la inyección de las dependencias aún no se ha producido *
* obviamente excluyendo la inyección de constructor
Ejemplo del 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
y @PreDestroy
se han eliminado por completo en Java 11 .
Para seguir usándolos, deberá agregar el JAR javax.annotation-api a sus dependencias.
<!-- 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.
verdadero con setter o inyección de campo, pero no verdadero con inyección de constructor.
Si su clase realiza toda su inicialización en el constructor, entonces @PostConstruct
es redundante.
Sin embargo, si su clase tiene sus dependencias inyectadas usando métodos setter, entonces el constructor de la clase no puede inicializar completamente el objeto, y algunas veces es necesario realizar alguna inicialización después de haber llamado a todos los métodos setter, de ahí el caso de uso de @PostConstruct
.
Considere el siguiente escenario:
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Dado que Car debe ser instanciado antes de la inyección de campo, el motor del punto de inyección sigue siendo nulo durante la ejecución del constructor, lo que resulta en una NullPointerException.
Este problema puede resolverse mediante la inyección de dependencia JSR-330 para la inyección del constructor Java o las anotaciones comunes JSR 250 para la anotación del método Java @PostConstruct.
@PostConstruct
JSR-250 define un conjunto común de anotaciones que se ha incluido en Java SE 6.
La anotación PostConstruct se usa en un método que debe ejecutarse después de realizar la inyección de dependencia para realizar cualquier inicialización. Este método DEBE invocarse antes de que la clase se ponga en servicio. Esta anotación DEBE ser compatible con todas las clases que admitan la inyección de dependencia.
JSR-250 Cap. 2.5 javax.annotation.PostConstruct
La anotación @PostConstruct permite la definición de los métodos que se ejecutarán después de que se haya instanciado la instancia y se hayan realizado todas las inyecciones.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
En lugar de realizar la inicialización en el constructor, el código se mueve a un método anotado con @PostConstruct.
El procesamiento de los métodos posteriores a la construcción es una simple cuestión de encontrar todos los métodos anotados con @PostConstruct e invocarlos a su 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);
}
});
}
El procesamiento de los métodos posteriores a la construcción debe realizarse después de que se hayan completado la creación de instancias y la inyección.
final
. Dado ese patrón, ¿por qué se@PostConstruct
agrega a J2EE, seguramente deben haber visto otro caso de uso?