En este artículo se siguen viendo más detalles de la declaración y uso de los beans. Recordando siempre que todos ellos son instanciados y gestionados por el contexto de Spring, produciéndose así la consabida inversión de control, al encargarse él de esas labores en vez de la aplicación.

Herencia

Si se tienen varios beans que comparten definiciones comunes, Spring permite utilizar un bean abstracto a modo de plantilla para evitar tener que repetir mucho código.

El bean utilizado como plantilla tiene que tener activo el atributo abstract. Y los beans que quieran utilizarlo como base para su propia definición deben referenciarlo a través del atributo parent.

<bean id="motocicleta" abstract="true">
  <property name="manillar" value="1"/>
  <property name="ruedas" value="2"/>
</bean>

<bean id="sidecar" class="..." parent="motocicleta">
  <property name="ruedas" value="3"/>
</bean>

Se siguen los principios de herencia habituales, por lo que las propiedades del padre son heredadas por los hijos y sobreescritas si se redefinen.

Referencias

En el artículo anterior se vieron algunas formas en las que un bean puede referenciar a otro. Como por ejemplo utilizando el «atributo» ref:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodService" ref="mexicanFood"/>
</bean>

Un método alternativo es utilizar la «etiqueta» ref:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodService">
    <ref bean="mexicanFood"/>
  </property>
</bean>

Esto permite referenciar cualquier bean instanciado desde cualquier fichero XML de configuración. No obstante se puede acotar la búsqueda a sólo los beans declarados dentro del fichero utilizando el atributo local:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodService">
    <ref local="mexicanFood"/>
  </property>
</bean>

Una opción algo distinta es utilizar idref, que sirve para referenciar el «nombre» de un bean. Es decir, para cargar la propiedad con el nombre del bean en vez de con el objeto al que referencia. Su uso es un tanto limitado, pero presenta la característica peculiar de que Spring es capaz de validar el nombre en el momento de hacer el despliegue en vez de provocar un error en tiempo de ejecución.

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodServiceName">
    <idref bean="mexicanFood"/>
  </property>
</bean>

Comentar que naturalmente Spring es capaz además de detectar referencias circulares y elevar una excepción en dicho caso.

Dependencias

Cuando se tiene un bean que depende de otro, sin necesidad de tener una propiedad que haga referencia a él, se puede utilizar el atributo depends-on para que Spring lo tenga en cuenta a la hora de inicializar e inyectar las dependencias.

Aunque parezca algo rebuscado, esto es algún común con algunas librerías, que requieren que se ejecute su constructor estático antes de poder utilizarlas.

<bean id="aplicacionBean" depends-on="libreriaBean"/>

Beans Internos

Si un bean va a utilizarse de forma puntual dentro de otro no hace falta declararlo de forma global. Se puede declarar como un bean interno de manera anónima, sin que ni siquiera necesite que se le asigne un identificador:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodService">
    <bean class="com.empresa.zoo.MexicanFoodServiceImpl"/>
  </property>
</bean>

Propiedades Internas

Se pueden inicializar propiedades internas indicando la ruta completa en el nombre. Por ejemplo, si un bean tiene una propiedad auditorio, y esta propiedad a su vez tiene una propiedad capacidadMaxima, se le puede asignar un valor directamente utilizando auditorio.capacidadMaxima como nombre:

<property name="auditorio.capacidadMaxima" value="250">

Se puede descender por la cadena utilizando la notación punto tantas veces como sea necesario.

Colecciones

Spring soporta también la instanciación e inicialización de colecciones. Es decir, es capaz de crear un objeto List, Map, Set, e incluso Properties, y rellenarlo con una serie de valores.

Imaginemos que nuestro zoológico tiene una lista de direcciones de correo de contacto:

public class ZooServiceImpl implements ZooService{

    private Map<String, String> emails;

    public void setEmails(Map<String, String> emails) {
        this.emails = emails;
    }
...

En vez de poner las direcciones de correo en el código se pueden ponerl en la configuración y dejar que Spring las inicialice.

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl">
  <property name="emails">
     <map>
       <entry key="tickets" value="tickets@zoo.com"/>
       <entry key="tours" value="tours@zoo.com"/>
       <entry key="manager" value="manager@zoo.com"/>
      </map>
  </property>
...

Spring soporta list, set, map y props. Y también tiene algunas características más avanzadas como la mezcla (merging) de colecciones para algunas configuraciones más complejas donde se pudiera llegar a necesitar.

Nulos

Se debe utilizar la etiqueta null para que una propiedad tome valor nulo:

<property name="hazmeNulo"><null/></property>

p-name y c-name

Una de las principales quejas que se hacen cuando se usa Spring es que los ficheros XML tienden a crecer bastante. Para intentar paliar este problema Spring permite utilizar una notación abreviada definida en dos namespaces llamados p-name, para las propiedades, y c-name, para los constructores.

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl"
      p:nombreZoo="Wild Park"
      p:foodService-ref="mexicanFood"/>

Veamos un ejemplo usando p-name para inicializar dos propiedades, por una parte una cadena de texto con el nombre del zoológico, y por otra parte una referencia a otro bean con el servicio de comidas:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl"
      p:nombreZoo="Wild Park"
      p:foodService-ref="mexicanFood"/>

Esta nomenclatura más compacta evita incluir las etiquetas property, permitiendo definir las propiedades dentro de la propia etiqueta bean. Notar que para referenciar a otro bean se utiliza la terminación -ref.

De igual forma, el namespace c-name permite abreviar la declaración de los contructores al definir los parámetros dentro de la propia etiqueta bean:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl"
      c:nombreZoo="Wild Park"
      c:foodService-ref="mexicanFood"/>

Si los nombres de los parámetros del constructor no están disponibles, porque no se compiló en modo debug, se pueden referenciar por su posición, con un guión bajo antepuesto para que el XML resultante sea válido:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl"
      c:_0="Wild Park"
      c:_1-ref="mexicanFood"/>

Los beans son una de las piezas claves dentro de Spring, motivo por el que se pueden declarar de formas tan distintas. Más información en el siguiente artículo de esta serie.