Spring 3 Java Config Style
Introducción
Creo que a estas alturas a nadie le voy a descubrir el framework de Spring y lo que ha aportado
a la comunidad Java/JEE sin pedir nada a cambio.
No obstante, es probable que las novedades de Spring 3 se nos hayan escapado, y es por eso que he decidido hacer una serie de
tutoriales comentando algunas de ellas.
Configuración de Spring
Antes de la versión 2.5 la única manera de configurar el contenedor de Spring era a través de ficheros XML.
Esta manera, que es por otro lado suficiente, a veces se puede convertir en un engorro al proliferar el número de «Beans» de nuestros proyectos.
Tras la aparición de las anotaciones en Java 1.5, Spring introdujo la posibilidad de configurar el contexto también a
través de éstas o combinando ambas. Yo suelo utilizar anotaciones para mis clases (las de mi proyecto)
y XML para las clases externas (no había más remedio, ya que no se «puede» anotar el código que no es mío)
A partir de Spring 3.0 aparece una nueva manera de configurar el contexto al estilo JavaConfig:
Configuración del contenedor con Java
Esta nueva forma de configurar el contenedor está basada principalmente en dos nuevas anotaciones y en una nueva implementación de ApplicationContext:
- @Configuration: Usar una anotación de este tipo en una clase sirve para indicarle a Spring que ésta es una clase contenedora
de definiciones de «Beans». Es importante hacer notar que una clase anotada con @Configuration será también registrada como «bean», y por lo tanto
también podremos usar las anotaciones de inyección de dependencias (@Autowired, @Inject o @Resource) - @Bean: Anotar un método de esta manera es equivalente a usar <bean> en un fichero de configuración tradicional de Spring.
Además no es imprescindible para poder usar esta anotación que la clase sea anotada con @Configuration, sino que también serán
«entendidas» aquellas que aparezcan en otras clases @Component (y por ende @Service, @Repository o @Controller) - AnnotationConfigApplicationContext: Esta clase será la encargada de levantar el contexto de Spring y entiende no sólo las anotaciones
tradicionales sino también las dos anteriores.
En el ejemplo que se muestra a continuación se muestran dos ejemplos de configuración que son equivalentes:
Estilo «Cocina tradicional»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <import resource="dao.xml"/> <bean id="beanA" class="com.autentia.tutoriales.A"> <constructor-arg ref="dataSource" /> </bean> <bean id="beanB" class="com.autentia.tutoriales.B"> <constructor-arg ref="beanA" /> </bean> </beans> |
Este es el dao.xml importado previamente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="XXX" /> <property name="url" value="XXX" /> <property name="username" value="XXX" /> <property name="password" value="XXX" /> </bean> </beans> |
Estilo «Nouvelle cuisine»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Configuration // Esta anotación es equivalente al import de xml @Import({DataSourceConfig.class}) public class SpringJavaConfigStyle { @Autowired private DataSource dataSource; @Bean public A beanA() { return new A(dataSource); } @Bean public B beanB() { return new B(beanA()); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Configuration public class DataSourceConfig { @Bean public DataSource dataSource() { Properties props = new Properties(); // Configuración de las propiedades // ... return new DriverManagerDataSource("XXX",props); } } |
Para levantar el contexto:
1 2 3 4 5 6 7 |
... public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringJavaConfigStyle.class); B b = ctx.getBean("beanB", B.class); ... } ... |
Otra opción equivalente para la inyección de dependencias, sería:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Configuration @Import({DataSourceConfig.class}) public class SpringJavaConfigStyle { @Autowired private DataSourceConfig dataSourceConfig; @Bean public A beanA() { return new A(dataSourceConfig.dataSource()); } @Bean public B beanB() { return new B(beanA()); } } |
Por otro lado, la anotación @Bean recibe diversos parámetros para configurar los nombres del «Bean»,
los métodos del ciclo de vida (init y destroy), y si queremos usar autowire en las propiedades del «Bean».
Usar el método «init» no tiene ya demasiado sentido porque se puede realizar después de la instanciación.
Además si queremos modificar el ámbito del «Bean», bastaría con usar la anotación @Scope:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Configuration @Import({DataSourceConfig.class}) public class SpringJavaConfigStyle { @Autowired private DataSourceConfig dataSourceConfig; @Bean public A beanA() { return new A(dataSourceConfig.dataSource()); } @Bean(name = { "beanB", "mrBean"}) @Scope("protoype") public B beanB() { return new B(beanA()); } } |
Mezclando XML y JavaConfig
Debido a que el estilo JavaConfig no es capaz de reemplazar completamente al estilo XML (principalmente por el tema de los namespaces),
conviene utilizar una combinación de ambas. Para poder hacer esto, como todo en Spring tenemos varias opciones, más en concreto dos:
El XML «manda»:
En este caso, usaremos una de las versiones de «XmlApplicationContext» y la cargaremos al estilo tradicional.
Pero para poder activar en este caso la búsqueda de anotaciones de configuración es necesario incluir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- Activa la búsqueda de anotaciones --> <context:annotation-config /> <!-- Registraremos el bean de configuración. El otro no es necesario porque se importa en la clase SpringJavaConfigStyle --> <bean class="com.autentia.tutoriales.config.SpringJavaConfigStyle"/> </beans> |
Si nos queremos ahorrar la definición de los beans de configuración en el XML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- Activa la búsqueda de anotaciones --> <context:annotation-config /> <!-- Le decimos donde buscar anotaciones de configuración --> <context:component-scan base-package="com.autentia.tutoriales.config"/> </beans> |
JavaConfig «manda»:
En este caso, debemos utilizar el mecanismo que hemos contado en los apartados anteriores (usando AnnotationConfigApplicationContext)
y utilizar la anotación @ImportResource:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Configuration @Import({DataSourceConfig.class}) @ImportResource("classpath:appContext.xml") public class SpringJavaConfigStyle { @Autowired private DataSourceConfig dataSourceConfig; @Bean public A beanA() { return new A(dataSourceConfig.dataSource()); } @Bean(name = { "beanB", "mrBean"}) @Scope("protoype") public B beanB() { return new B(beanA()); } } |
Carga del contexto vía JavaConfig en aplicaciones Web
Spring suele pensar en todo, y tal como se hacía para cargar el contexto de Spring en aplicaciones Web con XML, tenemos la versión
«JavaConfig manda» para cargar el contexto en aplicaciones Web. A continuación se muestra un ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <context-param> <param-name>contextClass</param-name> <param-value> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.autentia.tutoriales.config.SpringJavaConfigStyle</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app> |
Conclusiones:
La flexibilidad de la configuración del contexto de Spring queda sin ninguna duda completada con este
modelo nuevo basado en Java. Pero lo mejor de todo es la posibilidad de combinar las tres maneras de
configuración aportadas por Spring. Sabiendo las ventajas y los inconvenientes de cada una de ellas
podemos elegir la que mejor se adecúe a cada proyecto y a cada caso en particular:
Configuración XML
La configuración basada en XML es la más conveniente para configurar «beans» de infraestructura (DataSources, acceso a servicios…)
Ventajas:
- Configuración centralizada en uno o varios ficheros.
- Aplicable a todas las clases (nuestras y externas).
- De alguna manera, ya estamos familiarizados con esta forma de configuración.
Desventajas:
- Los ficheros se pueden volver algo engorrosos.
- Hay gente que «odia» el XML.
Configuración por Anotaciones
La configuración basada en anotaciones es ideal para «beans» muy cambiantes (controladores…)
Ventajas:
- Permite un desarrollo muy rápido.
- Todo está en la misma clase.
Desventajas:
- Evidentemente sólo podemos aplicarlo sobre nuestras clases.
- Podemos perder de vista la configuración al estar distribuida por todo nuestro código.
Configuración por JavaConfig
Este mecanismo proporciona un control total sobre la creación de Beans y configuración de los mismos.
Ventajas:
- Mayor velocidad en la carga del contexto.
- Gran flexibilidad ya que puede ser usada en todas las clases.
Desventajas:
- EL plugin de Spring (Spring Tool Suite) no puede representar la configuración de este tipo.
Grandísimo, a los favoritos de Twitter!
Buen tutorial para quiees apenas conocemos Spring
Estupendo tutorial Paco (casi tanto como tu foto)
Muchas gracias.