345 votes

Pourquoi utiliser @PostConstruct ?

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 ?

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 sont final 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).

479voto

Bozho Points 273663
  • 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.

24 votes

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).

8 votes

Quel est le cas où le constructeur d'un haricot peut être appelé plus d'une fois ?

2 votes

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à.

129voto

Andrea Ligios Points 16653

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.

Maven

<!-- 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>

Gradle

// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'

68voto

skaffman Points 197885

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 .

0 votes

@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/

12voto

Humoyun Points 2120

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.

1voto

struberg Points 447

De même, l'initialisation basée sur les constructeurs ne fonctionnera pas comme prévu lorsqu'un type de mandataire ou de remoting 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 lui...

Prograide.com

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.

Powered by:

X