Minimizar código con anotaciones en Spring.

3
41672

Cómo minimizar código Java y XML en Spring

0. Índice de
contenidos.

Este es el tercer tutorial de una serie que nos ayudará a dar los primeros pasos con el framework Spring 3.

  1. Spring Container e Inyección de Dependencias.
  2. Hola Mundo con Spring 3 MVC.

1. Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Mac Book Pro 17″ (2,93 Ghz Intel Core 2 Duo, 8 GB DDR3)
  • Sistema Operativo: Mac OS X Mountain Lion 10.8.5
  • Spring Framework 3.0

2. Introducción

Hemos visto cómo crear nuestras beans y cómo insertar las dependencias entre ellas a partir de un fichero XML. En este tutorial vamos a reducir la complejidad y la cantidad de líneas de código que hacen falta para configurar correctamente nuestros beans.

3. Vamos al lío

Como introducción partimos de la base de que queremos declarar un bean como el siguiente, y nos queremos ahorrar ciertos pasos.


	<bean id="coche" class="nuestroPath.vehiculoMotorizado">

		<property name="marca">
			<value>nuestroPath.marcas.laquesea</value>
		</property>      	
    	<property name="numeroRuedas" value="4"> 

	</bean>


Spring incorpora dos importantes características:

Autowiring reduce o incluso elimina la necesidad de configurar <property> o <contructor-arg> en nuestras beans.

Autodiscovery nos elimina la necesidad de declarar cada bean, ya que los busca en el path que le indiquemos y los encuentra gracias a las anotaciones que realizaremos en los propios objetos para indicar a spring qué tipo de bean es.

Para que funcione correctamente es necesario que esté correctamente indicado tanto las beans que queremos que encuentre o autodescubra, como las beans que queremos que nos inyecte, y no haya ambigüedades.

Autowiring tiene cuatro tipos por las que referenciar objetos, que son:

  • byName, tiene que coincidir el nombre o id con la propiedad.
  • byType, tiene que coincidir el mismo tipo de objeto con la propiedad a la que estamos inyectando.
  • constructor, intenta asignar a los parámetros del constructor las beans que encajen en tipo.
  • autodetect, intenta aplicar el tipo por constructor, si falla, lo intenta por el tipo byType.
byName

Para inidcar cada uno de los tipos, se indica como atributo al crear el bean así:


	<bean id="coche"
		class="vehiculoMotorizado" autowired="byName">
	</bean>

Además sabemos que coche tiene dos atributos, marca y numeroRuedas.

Ahora declaramos un bean como el siguiente:


	<bean id="marca"
		class="marcas.laquesea">
	</bean>

Spring reconoce por nombre que la propiedad de coche llamada marca coincide con la bean marca y al haber activado el atributo autowired=»byName», Spring tiene todo lo que necesita para enlazarlos. Nos hemos ahorrado definir esa propiedad dentro de la bean coche.

byType

Es similar a byName, pero en este caso, en vez de buscar las coincidencias entre los nombres de las beans y los nombres de los atributos a inyectar, se basa en el tipo de objeto que es cada uno. Lo explico mejor con un ejemplo:

En el mismo caso de antes, la propiedad numeroRuedas es un integer. Bataría con crear una bean de tipo integer como la siguiente para que Spring lo enlazara a coche.


	<bean id="numeroRuedas"
		class="java.lang.Integer" value="4">

Una cosa a tener en cuenta, es que si hay más de un bean que encaje en nuestro criterio de autowiring, Spring no va a saber cuál escoger, y saltará una excepción.

Para solucionar el problema hay dos maneras(dos propiedades dentro de las beans):

  • Primary: Es un valor booleano en el cual indica si esa bean es prioritaria para autowired, el problema es que por defecto todas las beans vienen con el atributo a true, por lo que para elegir una se tiene que poner a false este atributo en todas las demás.
  • Autowire-candidate: Es un valor booleano, que si está false indica que no se tiene en cuenta a la hora de elegir beans
Autowired por constructor

Solo válido si la bean está configurada para la inyección de dependencias. Tiene las mismas restricciones que byType. Además hay que tener en cuenta que si tiene varios constructores que puede satisfacer Spring, no sabrá cuál usar.

Su declaración es:


	<bean id="coche"
		class="vehiculoMotorizado" autowire="constructor">

Se puede poner un autowired por default, declarándolo cuando se instancia beans.

Por ejemplo:


	<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" 
	default-autowire="byType" >

	... declaración de beans ...

	</beans>

Y por último decir que también se puede hacer mixto, declarar las propiedades o los argumentos del constructor manualmente en el bean y los que se quiera que enlace Spring dejarlos sin declarar.

Teniendo en cuenta que para inicializar un atributo a null se haría como en el atributo marca:


	<bean id="coche"
		class="vehiculoMotorizado" 
		<property name="marca"><null/></property>
		<property name="numeroRuedas" value="4">

Anotaciones

A partir de Spring 2.5 la manera más interesante de enlazar nuestras beans es a través de las anotaciones.

Para decirle a Spring que use las anotaciones, se le indica con el elemento <context:annotation-config/>. Veámos un ejemplo:


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


	<context:annotation-config/>

	... declaración de beans ... 

	</beans>

Con <context:annotation-config/> le decimos a Spring que estamos usando anotaciones en nuestras clases java para enlazar los valores de las propiedades, métodos o constructores.

Spring 3.0 soporta 3 diferentes anotaciones para autowiring:

  • @Autowired
  • @Inject
  • @Resource

Las tres anotaciones se pueden usar indistintamente y prácticamente tienen la misma funcionalidad, pero tienen pequeñas variaciones de comportamiento que se salen del tutorial explicarlas, por lo que haremos los ejemplos con @Autowired y recomiendo revisar la página de SpringFramework para obtener toda la información que falte en este tutorial.

Usaremos @Autowired principalmente en tres casos:

  • Delante de un método, encontes acutará como si marcamos en el XML que inyecte una property de un bean. Ejemplo:
      		@Autowired
      		public void setMarca(Marca marca){
      			this.marca = marca;
      		}
    
      	
  • Ponerlo delante de una variable, obteniendo el mismo resultado que en el caso anterior:
      	
      		@Autowired
      		Marca marca;
    
      	
  • Y por último veremos cómo se puede poner antes de un constructor de una clase, que será como si se indica por XML que inyecte en el constructor de la bean correspondiente, como vimos antes.
      		@Autowired
      		public coche(Marca marca){
      			this.marca = marca;
      		}
    
      	

Es muy recomendable que se revise la anotación @Qualifying (@Named para @Inject) para personalizar la forma de inyectar las beans ajustándolas a nuestros requisitos. Se sale del temario de este tutorial para no hacerle excesivamente extenso.

Descubrimiento automático de beans.

Para que Spring automáticamente busque las beans sin describirlas en el XML es necesario cambiar la declaración <context:annotation-config> por <context:component-scan>. Además hace falta indicarle la base del paquete donde queramos que busque. Ejemplo:


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


	<context:component-scan
		base-package="ruta.paqueteAplicacion">
	</context:component-scan>

	... declaración de beans ...

	</beans>

Con eso buscaría en nuestra ruta todos los archivos java que en su interior tengas estas anotaciones (además de otras):

  • @Component: Es de propósito general, indica que la clase es un componente Spring.
  • @Controller: Indica que la clase define un controlador Spring.
  • @Repository: La clase es un repositorio de datos.
  • @Service: La clase define un servicio.

Conclusiones

Spring es un framework que nos evita muchos problemas y elimina dependencias. Además la comunidad que lo mantiene contínuamente está sacando mejoras.

Cualquier duda o sugerencia en la zona de comentarios.

Saludos.

3 COMENTARIOS

  1. Buenos días.

    Estoy empezando desde cero con un proyecto en Spring. Debo de tener problemas de configuración o que me falta algún plugin, porque todas las anotaciones que se comentan en este blog, Spring Tool Suite (STS) no las reconoce. El error que dice es el siguiente: «Autowired no se puede resolver como un tipo. ¿me pueden ayudar con este tema?

    Muchas gracias.

    • lo solucionaste? debes agregar las librerias correspondientes
      commons-loggin-1.2.jar
      spring-beans-4.2.6.RELEASE.jar
      spring-context-4.2.6.REALEASE.jar
      spring-core-4.2.6.RELEASE.jar
      spring-expression-4.2.6.RELEASE.jar
      spring-aop.4.2.6.RELEASE.jar

  2. Hola muy interesante articulo!
    Una consulta, si estoy utilizando spring version 4.2.5, que version deberia utilizar con spring secuirty o apache cxf; es decir, como reconocer que version utilizar con cada dependencia.
    Gracias de antemano.

    Buenas tardes!

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad