Dans un haricot géré, @PostConstruct
est appelé après le constructeur normal d'un objet Java.
Pourquoi j'utiliserais @PostConstruct
pour initialiser par le bean, au lieu du constructeur régulier lui-même ?
Dans un haricot géré, @PostConstruct
est appelé après le constructeur normal d'un objet Java.
Pourquoi j'utiliserais @PostConstruct
pour initialiser par le bean, au lieu du constructeur régulier lui-même ?
car lorsque le constructeur est appelé, le haricot n'est pas encore initialisé, c'est-à-dire qu'aucune dépendance n'est injectée. Dans l'environnement @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 seule 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 la méthode @PostConstruct
ne sera invoqué qu'une seule fois.
Dans le cas où le constructeur lui-même s'approprie toutes les dépendances - alors le haricot peut aussi être initialisé complètement dans le constructeur (après avoir défini manuellement tous les champs appropries).
Probablement quelque chose comme "passivation". Si le conteneur décide de stocker le haricot sur le magasin de disques et de le restaurer à partir de là.
El principal Le problème est le suivant :
dans un constructeur, l'injection des dépendances n'a pas encore eu lieu*.
*excluant évidemment l'injection de constructeur
Exemple concret :
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
y @PreDestroy
ont été complètement supprimé dans Java 11 .
Pour continuer à les utiliser, vous devrez ajouter l'option javax.annotation-api JAR à 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 toute son initialisation dans le constructeur, alors @PostConstruct
est en effet redondant.
Cependant, si votre classe a ses dépendances injectées en utilisant des méthodes de 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 que toutes les méthodes de setter ont été appelées, d'où le cas d'utilisation de @PostConstruct
.
@staffman : plus un de mon côté. Si je souhaite initialiser un champ inputtext avec une valeur extraite de la base de données, je peux le faire à l'aide de PostConstruct, mais j'échoue lorsque j'essaie de faire la même chose dans le constructeur. J'ai cette exigence d'initialiser sans l'utilisation de PostContruct. Si vous avez le temps, pouvez-vous répondre à cette question également ? stackoverflow.com/questions/27540573/
Considérons le scénario suivant :
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Étant donné que Car doit être instancié avant l'injection de champ, le moteur du point d'injection est toujours nul pendant l'exécution du constructeur, ce qui entraîne une NullPointerException.
Ce problème peut être résolu soit par JSR-330 Injection de dépendances pour Java ou JSR 250 Common Annotations 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épendances afin d'effectuer une quelconque initialisation. Cette méthode DOIT être invoquée avant que la classe soit placée en service. Cette annotation DOIT être supportée par toutes les classes qui supportent l'injection de dépendances.
JSR-250 Chap. 2.5 javax.annotation.PostConstruct
L'annotation @PostConstruct permet de définir des 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 simplement à trouver toutes les méthodes annotées avec @PostConstruct et à les invoquer à tour de rôle.
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é après l'instanciation et l'injection.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
7 votes
J'ai eu l'impression que l'injection de constructeur était généralement préférée pour permettre aux dépendances d'être
final
. Compte tenu de ce schéma, pourquoi@PostConstruct
ajouté à J2EE - ils ont dû voir un autre cas d'utilisation, sûrement ?0 votes
@mjaggard je crois savoir que
@PostConstruct
n'est pas utilisé pour injecter vos dépendances de manière appropriée, pour s'assurer qu'elles sontfinal
etc ; il est utilisé comme annotation pour un utilitaire qui devrait être appelé exactement une fois même si l'objet est construit plusieurs fois par le conteneur IoC. Je ne sais pas comment cela pourrait se produire dans le conteneur, mais cela peut apparemment arriver (voir la réponse acceptée).