Comment appeler une méthode une fois l'initialisation du bean terminée?

237

J'ai un cas d'utilisation où j'ai besoin d'appeler une méthode (non statique) dans le bean une seule fois lors du chargement d'ApplicationContext. Est-ce correct si j'utilise MethodInvokingFactoryBean pour cela? Ou nous avons une meilleure solution?

En remarque, j'utilise ConfigContextLoaderListener pour charger le contexte d'application dans l'application Web. Et que si le bean 'A' est instancié, il suffit d'appeler methodA () une fois.

Comment cela peut-il être bien fait?

Peakit
la source

Réponses:

196

Vous pouvez utiliser quelque chose comme:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

Cela appellera la méthode "init" lorsque le bean est instancié.

Mercer Traieste
la source
15
postConstruct devrait être mieux dans la plupart des cas, car nous ne voulons pas gâcher l'initialisation du bean Spring.
lwpro2
4
@ lwpro2 Que voulez-vous dire par "ne veux pas gâcher l'initialisation du bean Spring" ici?
Yngve Sneen Lindal
@Mercer Traieste que dois-je donner pour l'attribut class ici? Puis-je donner la classe de contrôleur ici?
KJEjava48
314

Pour développer la suggestion @PostConstruct dans d'autres réponses, c'est vraiment la meilleure solution, à mon avis.

  • Il garde votre code découplé de l'API Spring (@PostConstruct est en javax. *)
  • Il annote explicitement votre méthode init comme quelque chose qui doit être appelé pour initialiser le bean
  • Vous n'avez pas besoin de vous rappeler d'ajouter l'attribut init-method à votre définition de bean Spring, Spring appellera automatiquement la méthode (en supposant que vous enregistrez l'option annotation-config ailleurs dans le contexte, de toute façon).
skaffman
la source
9
Merci, ça marche. Notez que si vous souhaitez utiliser avec Spring, vous devez inclure "<context: annotation-config />" pour enregistrer le bean CommonAnnotationBeanPostProcessor (comme mentionné ci-dessus)
khylo
2
Une solution appropriée <context:component-scan>fonctionne également et peut être utile pour réduire le temps de démarrage si vous avez de grandes bibliothèques non Spring sur votre chemin de classe.
Donal Fellows
5
Le JavaDoc pour PostConstruct indique qu'une seule méthode peut être annotée avec lui par classe: docs.oracle.com/javaee/5/api/javax/annotation/…
Andrew Swan
@PostConstruct ne fonctionne pas avec un gestionnaire transactionnel, voir: forum.spring.io/forum/spring-projects/data/…
mmm
2
@PostConstruct ne vous sera pas non plus très utile lorsque le bean que vous instanciez n'est pas une classe à part, mais une classe tierce
John Rix,
102

Il y a trois approches différentes à considérer, comme décrit dans la référence

Utiliser l'attribut init-method

Avantages:

  • Ne nécessite pas de bean pour implémenter une interface.

Les inconvénients:

  • Aucune indication immédiate que cette méthode n'est requise après la construction pour garantir que le bean est correctement configuré.

Implémenter InitializingBean

Avantages:

  • Pas besoin de spécifier la méthode init ou d'activer le traitement de numérisation / annotation des composants.
  • Convient aux beans fournis avec une bibliothèque, où nous ne voulons pas que l'application utilisant cette bibliothèque se préoccupe du cycle de vie du bean.

Les inconvénients:

  • Plus invasive que l'approche init-method.

Utiliser l' annotation de style de vie JSR-250 @PostConstruct

Avantages:

  • Utile lors de l'utilisation de l'analyse de composants pour détecter automatiquement les beans.
  • Indique clairement qu'une méthode spécifique doit être utilisée pour l'initialisation. L'intention est plus proche du code.

Les inconvénients:

  • L'initialisation n'est plus spécifiée de manière centralisée dans la configuration.
  • Vous devez vous rappeler d'activer le traitement des annotations (qui peut parfois être oublié)
boîte à outils
la source
4
Je pense que c'est en fait une bonne chose à utiliser @PostConstructprécisément parce qu'il fait partie de la classe qu'il a besoin de la méthode appelant à la fin du traitement d'initialisation.
Donal Fellows
Si cette classe en a VRAIMENT besoin et que vous ne pouvez pas le faire dans le constructeur, je considère que c'est une odeur de code.
user482745
39

Avez-vous essayé d'implémenter InitializingBean? Cela ressemble exactement à ce que vous recherchez.

L'inconvénient est que votre bean devient compatible avec Spring, mais dans la plupart des applications, ce n'est pas si mal.

Jon Skeet
la source
2
Y a-t-il une raison pour laquelle vous choisiriez d'implémenter l'interface plutôt que de spécifier une méthode init dans le XML?
Mark
4
C'est une question de goût. L'interface fait partie du modèle de composant Spring et sert à cela et uniquement à cette fin, alors que pour une méthode nommée personnalisée, il n'est pas vraiment évident qu'elle doit être appelée pour terminer le cycle de vie du composant. Cela sert donc principalement la communication. Bien sûr, avec l'inconvénient de la dépendance introduite dans le framework Spring. Une bonne manière entre les deux est l'utilisation de @PostConstruct, car il a une sémantique claire mais n'introduit pas la dépendance ...
Oliver Drotbohm
7
Oliver me donne de bonnes excuses, mais je venais juste d'oublier la méthode init :) Une autre raison est que le type lui-même sait qu'il doit être "terminé" après que toutes les propriétés ont été définies - ce n'est pas fondamentalement quelque chose qui devrait être dans la configuration.
Jon Skeet
8

Vous pouvez déployer un BeanPostProcessor personnalisé dans votre contexte d'application pour le faire. Ou si cela ne vous dérange pas d'implémenter une interface Spring dans votre bean, vous pouvez utiliser l' interface InitializingBean ou la directive "init-method" (même lien).

Rob H
la source
Quelqu'un a-t-il des détails sur la façon d'écrire un BeanPostProcessor. Cela semble être exactement ce dont j'ai besoin. A
bientôt
Navires de printemps avec de nombreux exemples. Regardez simplement l'API JavaDoc pour BeanPostProcessor et vous trouverez des liens vers de nombreuses classes d'implémentation. Regardez ensuite le code source pour eux.
Rob H
-7

Pour clarifier davantage toute confusion concernant les deux approches, à savoir

  1. @PostConstruct et
  2. init-method="init"

Par expérience personnelle, j'ai réalisé que l'utilisation de (1) ne fonctionne que dans un conteneur de servlet, tandis que (2) fonctionne dans n'importe quel environnement, même dans les applications de bureau. Donc, si vous utilisez Spring dans une application autonome, vous devez utiliser (2) pour exécuter cet "appel de cette méthode après l'initialisation.

Ayorinde
la source
4
Techniquement, @PostConstruct(lorsqu'il est utilisé dans une application Spring) est lié à la durée de vie du contexte Spring propriétaire. Ces contextes peuvent être utilisés dans toutes sortes d'applications.
Donal Fellows
C'était le comportement que j'attendais mais ne fonctionnait pas pour moi.
Ayorinde