Risposte:
perché quando viene chiamato il costruttore, il bean non è ancora inizializzato, ovvero non vengono iniettate dipendenze. Nel @PostConstruct
metodo il bean è completamente inizializzato ed è possibile utilizzare le dipendenze.
perché questo è il contratto che garantisce che questo metodo verrà invocato una sola volta nel ciclo di vita del bean. Può accadere (sebbene improbabile) che un bean sia istanziato più volte dal contenitore nel suo funzionamento interno, ma garantisce che @PostConstruct
verrà invocato una sola volta.
Il problema principale è che:
in un costruttore, l'iniezione delle dipendenze non è ancora avvenuta *
* ovviamente esclusa l'iniezione del costruttore
Esempio nel mondo reale:
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
sono stati completamente rimossi in Java 11 .
Per continuare a usarli, devi aggiungere il JAR javax.annotation-api alle tue dipendenze.
<!-- 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.
vero con l'iniezione del setter o del campo, ma non vero con l'iniezione del costruttore.
Se la tua classe esegue tutta la sua inizializzazione nel costruttore, allora @PostConstruct
è davvero ridondante.
Tuttavia, se la tua classe ha le sue dipendenze iniettate usando i metodi setter, allora il costruttore della classe non può inizializzare completamente l'oggetto, e qualche volta l'inizializzazione deve essere eseguita dopo che tutti i metodi setter sono stati chiamati, quindi il caso d'uso di @PostConstruct
.
Considera il seguente scenario:
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Poiché Car deve essere istanziato prima dell'iniezione sul campo, il motore del punto di iniezione è ancora nullo durante l'esecuzione del costruttore, con conseguente NullPointerException.
Questo problema può essere risolto tramite JSR-330 Dependency Injection per l' iniezione del costruttore Java o JSR 250 Common Annotations per l'annotazione del metodo Java @PostConstruct.
@PostConstruct
JSR-250 definisce un insieme comune di annotazioni che è stato incluso in Java SE 6.
L'annotazione PostConstruct viene utilizzata su un metodo che deve essere eseguito dopo l'iniezione di dipendenza per eseguire qualsiasi inizializzazione. Questo metodo DEVE essere invocato prima che la classe venga messa in servizio. Questa annotazione DEVE essere supportata su tutte le classi che supportano l'iniezione delle dipendenze.
JSR-250 Cap. 2.5 javax.annotation.PostConstruct
L'annotazione @PostConstruct consente di definire i metodi da eseguire dopo che l'istanza è stata istanziata e tutti gli iniezioni sono stati eseguiti.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
Invece di eseguire l'inizializzazione nel costruttore, il codice viene spostato in un metodo annotato con @PostConstruct.
L'elaborazione dei metodi post-costruzione è una semplice questione di trovare tutti i metodi annotati con @PostConstruct e invocarli a loro volta.
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);
}
});
}
L'elaborazione dei metodi post-costruzione deve essere eseguita dopo che l'istanza e l'iniezione sono state completate.
final
. Dato questo schema, perché viene@PostConstruct
aggiunto a J2EE - devono aver visto sicuramente un altro caso d'uso?