Dans un bean géré, @PostConstruct
est appelé après le constructeur d'objet Java standard.
Pourquoi devrais-je utiliser @PostConstruct
pour initialiser par bean au lieu du constructeur standard lui-même?
parce que lorsque le constructeur est appelé, le bean n’est pas encore initialisé - c’est-à-dire qu’aucune dépendance n’est injectée. Dans la méthode @PostConstruct
, le bean est complètement initialisé et vous pouvez utiliser les dépendances.
car c’est le contrat qui garantit que cette méthode ne sera invoquée qu’une fois dans le cycle de vie du bean. Il peut arriver (bien que cela soit peu probable) qu'un bean soit instancié plusieurs fois par le conteneur dans son fonctionnement interne, mais cela garantit que @PostConstruct
ne sera invoqué qu'une seule fois.
Le problème principal est le suivant:
dans un constructeur, l'injection des dépendances n'a pas encore eu lieu *
* évidemment à l'exclusion de l'injection de constructeur
Exemple du monde réel:
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
}
}
IMPORTANT: @PostConstruct
et @PreDestroy
ont été complètement supprimé dans Java 11.
Pour continuer à les utiliser, vous devez ajouter le fichier JAR javax.annotation-api à vos dépendances.
<!-- 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'
Si votre classe effectue toutes ses initialisations dans le constructeur, alors @PostConstruct
est en effet redondant.
Cependant, si les dépendances de votre classe sont injectées à l'aide de méthodes setter, alors le constructeur de la classe ne peut pas initialiser complètement l'objet, et parfois une certaine initialisation doit être effectuée après l'appel de toutes les méthodes setter, d'où le cas d'utilisation de @PostConstruct
. .
Considérez le scénario suivant:
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Etant donné que Car doit être instancié avant l'injection sur le terrain, le moteur du point d'injection est toujours nul pendant l'exécution du constructeur, ce qui entraîne une exception NullPointerException.
Ce problème peut être résolu soit par , soit par injection de constructeur JSR-330 Dependency Injection pour Java , soit par annotation commune JSR 250 pour l'annotation de méthode Java @PostConstruct.
@ PostConstruct
JSR-250 définit un ensemble commun d'annotations qui a été inclus dans Java SE 6.
L'annotation PostConstruct est utilisée sur une méthode qui doit être exécutée après l'injection de dépendance pour effectuer toute initialisation. Cette méthode DOIT être invoquée avant la mise en service de la classe. Cette annotation DOIT être prise en charge sur toutes les classes prenant en charge l'injection de dépendances.
JSR-250 Chap. 2.5 javax.annotation.PostConstruct
L'annotation @PostConstruct permet de définir les méthodes à exécuter après l'instanciation de l'instance et l'exécution de toutes les injections.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
Au lieu d'effectuer l'initialisation dans le constructeur, le code est déplacé vers une méthode annotée avec @PostConstruct.
Le traitement des méthodes post-construction consiste à trouver toutes les méthodes annotées avec @PostConstruct et à les invoquer à leur tour.
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);
}
});
}
Le traitement des méthodes post-construction doit être effectué une fois l’instanciation et l’injection terminées.
En outre, l'initialisation basée sur le constructeur ne fonctionnera pas comme prévu lorsqu'un type de proxy ou d'accès distant est impliqué.
Le ct sera appelé chaque fois qu'un EJB sera désérialisé, et chaque fois qu'un nouveau proxy sera créé pour celui-ci ...