¿Cómo llamar a un método después de completar la inicialización del bean?

237

Tengo un caso de uso donde necesito llamar a un método (no estático) en el bean solo una vez en la carga de ApplicationContext. ¿Está bien si uso MethodInvokingFactoryBean para esto? ¿O tenemos una solución mejor?

Como nota al margen, uso ConfigContextLoaderListener para cargar el contexto de la aplicación en la aplicación web. Y quiero, que si se crea una instancia del bean 'A' solo llame al método A () una vez.

¿Cómo se puede hacer esto bien?

pico
fuente

Respuestas:

196

Puedes usar algo como:

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

Esto llamará al método "init" cuando se instancia el bean.

Mercer Traieste
fuente
15
Sin embargo, postConstruct debería ser mejor en la mayoría de los casos, ya que no queremos estropear la inicialización de Spring Bean.
lwpro2
44
@ lwpro2 ¿Qué quiere decir con "no quiero estropear la inicialización del frijol de primavera" aquí?
Yngve Sneen Lindal
@ Mercer Traieste, ¿qué debo dar para el atributo de clase aquí? ¿Puedo dar la clase de controlador aquí?
KJEjava48
314

Para ampliar la sugerencia de @PostConstruct en otras respuestas, esta es realmente la mejor solución, en mi opinión.

  • Mantiene su código desacoplado de la API de Spring (@PostConstruct está en javax. *)
  • Anota explícitamente su método init como algo que debe llamarse para inicializar el bean
  • No necesita recordar agregar el atributo init-method a su definición de spring bean, spring llamará automáticamente al método (suponiendo que registre la opción annotation-config en cualquier otro lugar del contexto, de todos modos).
skaffman
fuente
99
Gracias, esto funciona. Tenga en cuenta que si desea usar con Spring debe incluir "<context: annotation-config />" para registrar el bean CommonAnnotationBeanPostProcessor (como se mencionó anteriormente)
khylo
2
Un adecuado <context:component-scan>también funciona y puede ser útil para reducir el tiempo de inicio si tiene grandes bibliotecas que no sean Spring en su classpath.
Donal Fellows
55
JavaDoc para PostConstruct dice que solo se puede anotar un método por clase: docs.oracle.com/javaee/5/api/javax/annotation/…
Andrew Swan
@PostConstruct no funciona con un administrador de transacciones, consulte: forum.spring.io/forum/spring-projects/data/…
mmm
2
@PostConstruct tampoco será de mucha utilidad para usted cuando el bean que está creando instancias no sea una clase propia, sino una clase de terceros
John Rix
102

Hay tres enfoques diferentes a considerar, como se describe en la referencia

Utilice el atributo init-method

Pros:

  • No requiere bean para implementar una interfaz.

Contras:

  • No se requiere una indicación inmediata de este método después de la construcción para garantizar que el bean esté configurado correctamente.

Implementar InitializingBean

Pros:

  • No es necesario especificar el método init o activar el escaneo de componentes / procesamiento de anotaciones.
  • Apropiado para beans suministrados con una biblioteca, donde no queremos que la aplicación que utiliza esta biblioteca se preocupe por el ciclo de vida del bean.

Contras:

  • Más invasivo que el enfoque del método init.

Utilice la anotación de ciclo de vida JSR-250 @PostConstruct

Pros:

  • Útil cuando se usa el escaneo de componentes para autodetectar beans.
  • Deja en claro que se debe usar un método específico para la inicialización. La intención está más cerca del código.

Contras:

  • La inicialización ya no se especifica centralmente en la configuración.
  • Debe recordar activar el procesamiento de anotaciones (que a veces puede olvidarse)
kit de herramientas
fuente
44
Creo que es realmente bueno usarlo @PostConstructprecisamente porque es parte de la clase que necesita que el método llame al final del proceso de inicialización.
Donal Fellows
Si esa clase REALMENTE lo necesita y no puede hacerlo en constructor, entonces considero que es olor a código.
user482745
39

¿Has intentado implementar InitializingBean? Parece exactamente lo que buscas.

La desventaja es que su bean se vuelve consciente de Spring, pero en la mayoría de las aplicaciones eso no es tan malo.

Jon Skeet
fuente
2
¿Hay alguna razón por la que elegiría implementar la interfaz en lugar de especificar un método init en el XML?
Marcar el
44
Eso es cuestión de gustos. La interfaz es parte del modelo de componentes Spring y sirve para ese propósito y solo para un método con nombre personalizado, puede que no sea realmente obvio que deba llamarse para completar el ciclo de vida del componente. Esto sirve principalmente a la comunicación. Por supuesto, con el inconveniente de la dependencia introducida en el marco de Spring. Una buena manera en el medio es el uso de @PostConstruct, ya que tiene una semántica clara, pero no introduce la dependencia ...
Oliver Drotbohm
77
Oliver me da algunas buenas excusas, pero realmente me había olvidado del método init :) Otra razón es que el tipo en sí mismo sabe que necesita ser "terminado" después de que se hayan establecido todas las propiedades, no es fundamentalmente algo que debería estar en la configuración.
Jon Skeet el
8

Puede implementar un BeanPostProcessor personalizado en el contexto de su aplicación para hacerlo. O si no le importa implementar una interfaz Spring en su bean, puede usar la interfaz InitializingBean o la directiva "init-method" (mismo enlace).

Rob H
fuente
¿Alguien tiene detalles sobre cómo escribir un BeanPostProcessor. Eso suena a ser exactamente lo que necesito. Saludos :)
Peakit
La primavera se envía con muchos ejemplos. Solo mire la API JavaDoc para BeanPostProcessor y encontrará enlaces a muchas clases de implementación. Luego mire el código fuente para ellos.
Rob H
-7

Para aclarar aún más cualquier confusión sobre los dos enfoques, es decir, el uso de

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

Por experiencia personal, me di cuenta de que usar (1) solo funciona en un contenedor de servlets, mientras que (2) funciona en cualquier entorno, incluso en aplicaciones de escritorio. Entonces, si usaría Spring en una aplicación independiente, tendría que usar (2) para llevar a cabo esa llamada a este método después de la inicialización.

Ayorinde
fuente
44
Técnicamente, @PostConstruct(cuando se usa en una aplicación basada en Spring) está vinculada a la vida útil del contexto Spring propio. Tales contextos se pueden usar en todo tipo de aplicaciones.
Donal Fellows
Ese era el comportamiento que esperaba pero no funcionó para mí.
Ayorinde