Spring BeanPostProcessor

0
7517

Spring BeanPostProcessor

Índice de contenidos

1. Introducción
2. Entorno
3. Creando un BeanPostProcessor
4. Probando la solución
5. BeanFactoryPostProcessor s
6. Referencias

1. Introducción

En este tutorial se va a explicar cómo extender la funcionalidad del contenedor IoC (Inversion of Control) de Spring mediante la definición de BeanPostProcessor s.
Si no sabéis qué es el contenedor IoC, podéis consultar la documentación de Spring aquí.

Muchos desarrolladores no conocen el concepto de BeanPostProcessor, y sin embargo los están usando en sus aplicaciones basadas en Spring, sin tener constancia de ello. Es muy importante conocer dichos beans, no sólo para para tener más claro el ciclo de vida de los beans en Spring, sino porque ofrece múltiples ventajas. Definamos primero qué es un BeanPostProcessor:

Un BeanPostProcessor es un bean de Spring que permite extender la funcionalidad del contenedor IoC para agregar lógica de instanciación, lógica de resolución de dependencias (beans colaboradores), etc.
A nivel de implementación, BeanPostProcessor no es más que una interfaz que define dos métodos:

Éstos métodos callback serán llamados por el contenedor IoC antes (postProcessBeforeInitialization) y después (postProcessAfterInitialization) de la instanciación, inicialización y configuración de cada uno de los beans del contenedor. Esto ocurre para cada uno de los BeanPostProcessor s definidos en el contexto de Spring.

Se pueden configurar múltiples BeanPostProcessors y se puede controlar el orden en el que éstos son ejecutados, mediante la propiedad ‘order’ (ya veremos más adelante como hacer que un BeanPostProcessor personalizado sea ordenable). El contenedor de Spring cargará de forma automática los BeanPostProcessor s que encuentre en su contexto.

Es importante hacer notar que los BeanPostProcessor s actúan sobre los beans del ámbito del contenedor. Es decir que si se ha establecido una jerarquía de contextos en una aplicación, sólo actuarán sobre el contexto donde hayan sido definidos (ver Spring context hierarchies para más información).

Ventajas

Los BeanPostProcessor s nos ofrecen ventajas como las siguientes:

  • Nos permiten extender la funcionalidad del contenedor de IoC para añadir funcionalidad antes y/o después de la configuración de los beans del mismo.
  • Sirven de validadores para aquellos casos que no queramos que el contexto se cargue sin cumplir una serie de requisitos
  • Combinados con AOP (Aspect Oriented Programming), ofrecen muchas posibilidades de pre y post procesamiento

2. Entorno

Para la realización de este tutorial, se ha usado el siguiente entorno:

  • Macbook pro core i7 con 16gb RAM
  • SO: Mavericks
  • IDE: Spring Tool Suite 3.4.0 RELEASE
  • Spring 3.2.6 RELEASE
  • Maven 3.0.4

3. Creando un BeanPostProcessor

En este tutorial vamos a crear un par de BeanPostProcessor s. El primero simplemente imprimirá por pantalla el nombre del bean inicializado, y el segundo
comprobará si las propiedades de configuración de la aplicación están asignadas. Si no las están, se producirá una excepción que impedirá que el contexto de Spring se siga cargando.

Ambos beans implementarán la interfaz BeanPostProcessor y la interfaz Ordered para que el contenedor de Spring lo tenga en cuenta para ordenar su ejecución con respecto al resto de BeanPostProcessor s.

HelloWorldBeanPostProcessor.java

AppCfgBeanPostProcessor.java

Como podemos observar, ambas clases implementan la interfaz BeanPostProcessor, que la registrará automáticamente el contenedor de Spring como un BeanPostProcessor, y Ordered, que indicará que el BeanPostProcessor es ordenable dentro del contexto de Spring. Si no implementara dicha interfaz, se metería dentro del ‘cajón’ de beans no ordenables y se ejecutaría en el orden definido en el XML. Hay que tener también en cuenta que si se usa una configuración de Spring basada en Java (Spring 3.0+), la ordenación de los BeanPostProcessors se hará por el orden en el que fueron registrados en el contexto.

La clase que va a almacenar los datos de la configuración de la aplicación es la que sigue:

AppCfg.java

Como vemos, es simplemente una clase POJO con dos propiedades de ejemplo. Éstas propiedades las va a inyectar Spring mediante su definición en el archivo de contexto. He optado por usar la solución XML para la configuración de Spring, aunque se puede usar la configuración por Java (Spring 3.0+) y anotaciones @Autowired o @Reference (JSR-250). En nuestro caso, éstas propiedades serán inyectadas desde un archivo de propiedades que se encuentra en el classpath.

A continuación se muestra el archivo de configuración de contexto de Spring:

Aquí se está usando el componente property-placeholder de spring-context para cargar el archivo de propiedades y asignarlo en las propiedades del bean AppCfg. Este componente tiene un pequeño secreto, tal y como explicaré más adelante

El fichero de propiedades:

Por último, se muestra el fichero pom.xml de Maven.

4. Probando la solución

Siempre tenemos que realizar pruebas unitarias de nuestro desarrollo, por eso es buena práctica hacer TDD, y aquí no iba a ser menos:

BppTest.java

El test es muy sencillo. Primero carga el contexto de Spring (junto con nuestros nuevos BeanPostProcessors). Si no salta ninguna excepción, continúa la ejecución sacando por pantalla las dos propiedades de la aplicación de ejemplo.
Es importante fijarse que este test no comprueba funcionalidad más allá del contexto de Spring; toda la funcionalidad la maneja Spring dentro del contenedor de IoC, de forma que si ocurre alguna excepción dentro de nuestros BeanPostProcessors, la ejecución se detendrá y nuestro test fallará.

El contexto de aplicación de Spring usado para el test: applicationContext-test.xml es una copia del que he mostrado más arriba.

Ejecutamos el test con sólo la propiedad app.property1 asignada en el fichero de propiedades:

Lo volvemos a ejecutar con las dos propiedades asignadas:

En el proceso de depuración del test podemos ver que no sólo se ejecutan los métodos de nuestros dos nuevos BeanPostProcessors, sino que además Spring define una serie de BeanPostProcessors que se ejecutan para cualquier contexto: ApplicationContextAwareProcessor,BeanPostProcessorChecker, etc. No está en el ámbito de este tutorial explicar estos BeanPostProcessor s, aunque sí se pueden consultar en la documentación de Spring.

Podéis descargar el proyecto aquí

5. BeanFactoryPostProcessor

Existe en Spring un tipo de BeanPostProcessor especial llamado BeanFactoryPostProcessor. La semántica es la misma, pero la diferencia está en que este bean actúa sobre los metadatos del contexto de Spring, es decir, sobre el mismo archivo de configuración.

La interfaz tiene el siguiente método:

Recibe como parámetro el BeanFactory usado en el contexto de la aplicación.

Viendo el fichero de configuración de Spring de más arriba; ¿Recordáis el elemento property-placeholder? Ahora bien, la funcionalidad de este elemento es obtener todos los elementos ${} y aplicarles el valor de la propiedad del fichero properties. ¿Podéis pensar durante un momento cómo lo hace? Efectivamente. El elemento property-placeholder se trata de un BeanFactoryPostProcessor, que en su método postProcessBeanFactory realiza esta operativa.

Un ejemplo de BeanFactoryPostProcessor sería el siguiente (no implementado en el proyecto ejemplo):

6. Referencias

  • http://docs.spring.io/spring/docs/4.0.0.RELEASE/spring-framework-reference/htmlsingle/#beans-factory-extension-bpp
  • http://docs.spring.io/spring/docs/4.0.0.RELEASE/spring-framework-reference/htmlsingle/#beans-factory-extension-factory-postprocessors

Dejar respuesta

Please enter your comment!
Please enter your name here