Buenas practicas en la configuración de Spring

LIBP-0040 (Libro de pautas)

Uno de los mayores problemas en el uso del framework Spring es su complejidad en la creación y mantenimiento del XML que contiene la configuración.

 A continuación se ofrece un conjunto de pautas para realizar una configuración de Spring más eficiente.

Pautas

TítuloCarácter
Incluir las librerías de forma eficienteRecomendada
Usar convenciones de nomenclaturaRecomendada
Usar formas abreviadas de configuraciónObligatoria
Utilizar type en vez de index para los argumentos del constructorObligatoria
En lo posible, reutilizar definiciones de beansRecomendada
Integrar archivos de configuración mediante ApplicationContext y no utilizando importObligatoria
Usar ids como identificadores de beansObligatoria
Usar dependency-check durante la fase de desarrolloRecomendada
Agregar una descripción en el encabezado de cada archivo de configuraciónObligatoria
Comunicar los cambios al equipoRecomendada
Utilizar inyección de dependencias por Setter en vez de por ConstructorObligatoria
No abusar de la inyección de dependenciasRecomendada

Incluir las librerías de forma eficiente

A la hora de añadir las bibliotecas de Spring en nuestro proyecto, hemos de asegurarnos que si se tiene el JAR spring.jar, no se tienen que añadir también las bibliotecas spring-aop.jar y spring-dao.jar. Ambas están contenidas en la primera.

Usar convenciones de nomenclatura

Esta es la misma filosofía que utilizamos con el código Java. Usar una nomenclatura clara, descriptiva y consistente en todo el proyecto es de gran ayuda para que los desarrolladores entiendan la configuración XML. Para el id de los beans, por ejemplo, se puede seguir la convención de atributos de una clase Java. El bean ID de una instancia de InvasorDAO podría ser InvasorDAO. En proyectos grandes, se puede agregar el nombre del paquete como prefijo del bean ID.

Usar formas abreviadas de configuración

Las formas abreviadas son mas fáciles de leer, dado que transforma el valor de los elementos hijos en atributos del elemento padre. Por ejemplo:

<bean id="invasorService"
      class="MADEJA.spring.InvasorService">
       <property name="nombreInvasor">
          <value>Zim</value>
       </property>
       <constructor-arg>
          <ref bean="invasorDAO">
       </constructor-arg></bean>

puede ser reescrito de forma abreviada:

<bean id="InvasorService"
      class="MADEJA.spring.InvasorService">
        <property name="nombreInvasor" value="Zim"/>
        <constructor-arg ref="invasorDAO"/>
</bean>

Esta forma de abreviar nuestra configuración deja al archivo XML mucho más claro.

Utilizar type en vez de index para los argumentos del constructor

Spring permite utilizar índices (que comienzan en cero) para resolver el problema de ambigüedad cuando un constructor tiene más de un argumento del mismo tipo, o cuando se utiliza el atributo value para asignar el valor. Por ejemplo, en vez de:

<bean id="InvasorService"
        class="com.dosideas.spring.InvazorService">
        <constructor-arg index="0" value="Zim"/>
        <constructor-arg index="1" value="100"/>
</bean>

es mejor utilizar el atributo type de la siguiente manera:

<bean id="invasorService"
        class="com.dosideas.spring.InvasorService">
        <constructor-arg type="java.lang.String" value="Zim"/>
        <constructor-arg type="int" value="100"/>
</bean>

Utilizar index es más sencillo, ya que codificamos menos, pero es más propenso a errores y mucho mas difícil de leer que si utilizamos type. Se debería utilizar index solamente cuando se presenta una ambigüedad en los argumentos del constructor.

En lo posible, reutilizar definiciones de beans

Spring ofrece un mecanismo de pseudo-herencia que reduce la duplicación de información en los archivos de configuración. Una definición de un bean hijo puede heredar la información de configuración de sus padres, los cuales sirven como un "template" para los beans hijos. En grandes proyectos el uso de esta propiedad debería ser obligatorio. Todo lo que se necesita hacer es especificar la propiedad abstract=true en el bean padre y referenciar a dicho bean desde los beans hijos. Por ejemplo:

<bean id="abstractInvasorService" abstract="true"
        class="MADEJA.spring.AbstractInvasorService">
        <property name="nombreInvasor" value="Zim"/>
</bean>
<bean id="InvasorService"
        parent="abstractInvasorService"
        class="MADEJA.spring.InvasorService">
        <property name="robotAsignado" value="Gir"/>
</bean>

El bean InvasorService hereda el valor Zim para la propiedad nombreInvasor del bean abstractInvasorService. Una aclaración: Si no se especifica el nombre de una clase en un factory method en la definición de un bean, este bean es implícitamente abstracto.

Integrar archivos de configuración mediante ApplicationContext y no utilizando import

Al igual que el import en los scripts de Ant, el import en Spring es conveniente para unir archivos modularizados de configuración. Por ejemplo:

<beans>
        <import resource="InvasorServices.xml"/>
        <import resource="RobotsServices.xml"/>
         <bean id="PlanetaObjetivoService"
                 class="MADEJA.spring.PlanetaObjetivoService"/>
<beans>

En vez de unirlos dentro del XML utilizando imports, es mucho más flexible configurarlo a través del ApplicationContext. Utilizando ApplicationContext también hace que nuestra configuración XML sea más facil de manejar. Se le puede pasar como argumento al constructor de ApplicationContext una lista de archivos de configuración. Nuestro ejemplo anterior quedaría:

String&#91;&#93; serviceResources =
        {"PlanetaServices.xml",
        "InvasorServices.xml",
        "RobotServices.xml"};
ApplicationContext orderServiceContext = new
        ClassPathXmlApplicationContext(serviceResources);

Usar ids como identificadores de beans

Se puede especificar un name o un id como identificador de beans. Utilizar ids no incrementa la legibilidad, pero puede permitir que el analizador XML valide las referencias de los beans. Si los ids no pueden ser utilizados debido a alguna restricción XML IDREF, se pueden utilizar nombres como identificadores de beans. La restricción XML IDREF dice que los ids deben comenzar con una letra (o alguno de los pocos caracteres de signo de puntuación permitidos en la especificación XML) seguido de letras, dígitos, guiones, guiones bajos, dos puntos o punto. Es muy raro que en algún proyecto exista un problema con algún nombre por no cumplir con estas restricciones.

Usar dependency-check durante la fase de desarrollo

Se puede asignar al atributo dependency-check en la definición de un bean un valor destinto del asignado por defecto (none), como puede ser: simple, objects o all. Con esto, el contenedor puede realizar validaciones de dependencias. Esto es útil cuando todas las propiedades (o cierto grupo de propiedades) de un bean deben ser asignadas explícitamente (o por autowiring).

<bean id="invasorService"
        class="MADEJA.spring.InvasorService"
        dependency-check="objects">
        <property name="nombreInvasor" value="Zim"/>
        <constructor-arg ref="invasorDAO"/>
</bean>

En este ejemplo, el contendedor se asegurará que las propiedades de InvasorService que no sean primitivos o colecciones estén asignadas. Se puede configurar el chequeo de dependencias para que controle que todas las propiedades del bean estén asignadas, pero esto es necesario en raras ocasiones ya que puede que haya propiedades que no necesiten ser asignadas.

Agregar una descripción en el encabezado de cada archivo de configuración

Es preferible usar identificadores y nombres descriptivos en vez de utilizar comentarios en los archivos de configuración. Adicionalmente, es útil agregar un encabezado en los archivos de configuración, el cual englobe los beans definidos en el archivo. Por ejemplo:

<beans>
    <description>
        Este archivo define los Invasores que
        atacaran los disintos planetas. Depende
        de RobotsServices.xml, el cual provee los
        servicios de los robots que cada invasor tiene
        asignado....
    </description>    ...
</beans>

Comunicar los cambios al equipo

Cuando se esta refactorizando código Java, es necesario asegurarse de actualizar el archivo de configuración para que refleje los cambios realizados e informar estos cambios a los miembros del equipo. El archivo de configuración XML es parte del código y es una parte crítica de la aplicación. La mayoría de las veces es necesario leer tanto el archivo XML como el código Java para comprender cómo funciona algún componente.

Utilizar inyección de dependencias por Setter en vez de por Constructor

Spring provee tres tipos de inyección de dependencias: inyección por constructor, por setter y por método. Usualmente solamente utilizamos las dos primeras.

<bean id="invasorService" class="MADEJA.spring.InvasorService">
       <constructor-arg ref="invasorDAO"/>
</bean>
 <bean id="robotService" class="MADEJA.spring.RobotService">
        <property name="robotDAO" ref="robotDAO">
</bean>

En este ejemplo, el bean invasorService usa inyección por constructor, mientras que el bean robotService usa inyección por setter. La inyección de dependencias por constructor garantiza que el bean no será construido con un estado inválido, pero la inyección de dependencias por setters es mucho mas flexible, especialmente cuando la clase tiene muchas propiedades y la mayoría de ellas son opcionales.

No abusar de la inyección de dependencias

El ApplicationContext de Spring puede crear los objetos Java que sean necesarios, pero no todos los objetos deberían ser creados a través del motor de inyección de dependencias. Como ejemplo, los objetos de dominio no deberían ser creados utilizando inyección de dependencia. Los archivos de configuración pueden sobrecargarse mucho si no se controla bien el crecimiento de los beans definidos. Utilizar en exceso la inyección de dependencia puede hacer el archivo de configuración muy complicado y sobrecargado.