Autowiring Collaborators

Autoconexión de colaboradores

El contenedor de Spring puede autoconectar las relaciones entre beans colaboradores. Esto permite que Spring resuelva automáticamente otros beans requeridos al inspeccionar el contenido del ApplicationContext.

La autoconexión ofrece las siguientes ventajas:

  • Puede reducir de forma considerable la necesidad de declarar propiedades o argumentos de constructor.
  • Puede actualizar la configuración a medida que evolucionan los objetos. Por ejemplo, al añadir una dependencia a una clase, Spring puede satisfacerla sin modificar la configuración existente. Esto resulta especialmente útil durante el desarrollo, sin impedir que se cambie más adelante a una conexión explícita cuando el código sea más estable.

Modos de autoconexión

En la configuración basada en XML, se puede especificar el modo de autoconexión de cada definición de bean mediante el atributo autowire del elemento <bean/>.

Modo Explicación
no Es el valor predeterminado. No hay autoconexión; las referencias a beans deben declararse con elementos ref. En aplicaciones grandes suele ser preferible, porque las dependencias explícitas proporcionan mayor control, claridad y documentación de la estructura del sistema.
byName Autoconexión por nombre de propiedad. Spring busca un bean con el mismo nombre que la propiedad que se debe inyectar. Por ejemplo, si existe una propiedad master y un método setMaster(..), Spring busca un bean llamado master.
byType Autoconexión por tipo de propiedad. Solo funciona cuando existe exactamente un bean del tipo requerido en el contenedor. Si hay más de uno, se lanza una excepción; si no hay ninguno, la propiedad no se establece.
constructor Similar a byType, pero aplicado a los argumentos del constructor. Debe existir exactamente un bean para cada tipo de argumento requerido; de lo contrario, se produce un error.

Con los modos byType y constructor también se pueden inyectar arrays y colecciones tipadas. En ese caso, Spring proporciona todos los candidatos compatibles con el tipo esperado.

También se puede inyectar un Map tipado cuya clave sea String. Los valores del mapa serán las instancias de beans compatibles y las claves serán sus respectivos nombres de bean.

Ejemplo: autoconexión por nombre

En este ejemplo, Spring inyecta el bean llamado master en la propiedad master de client.

<bean id="master" class="com.example.Master"/>

<bean id="client" class="com.example.Client" autowire="byName"/>

La clase Client contiene una propiedad compatible:

public class Client {

    private Master master;

    public void setMaster(Master master) {
        this.master = master;
    }
}

Ejemplo: autoconexión por tipo

Cuando hay un único bean del tipo requerido, Spring puede inyectarlo automáticamente.

<bean id="primaryRepository" class="com.example.CustomerRepository"/>

<bean id="customerService"
      class="com.example.CustomerService"
      autowire="byType"/>
public class CustomerService {

    private CustomerRepository repository;

    public void setRepository(CustomerRepository repository) {
        this.repository = repository;
    }
}

Si hubiera más de un bean de tipo CustomerRepository, la autoconexión por tipo sería ambigua y Spring produciría un error.

Limitaciones y desventajas de la autoconexión

La autoconexión funciona mejor cuando se utiliza de forma coherente en todo el proyecto. Usarla solo en una o dos definiciones puede resultar confuso para quienes mantienen el código.

Considera las siguientes limitaciones:

  • Las dependencias explícitas declaradas mediante property y constructor-arg siempre tienen prioridad sobre la autoconexión.
  • No se pueden autoconectar propiedades simples, como tipos primitivos, String, Class ni arrays de esos tipos.
  • La autoconexión es menos precisa que la conexión explícita. Aunque Spring evita adivinar ante ambigüedades, las relaciones entre los objetos gestionados dejan de estar documentadas de forma directa.
  • Las herramientas que generan documentación a partir del contenedor de Spring pueden no disponer de la información de conexión.
  • Puede haber varias definiciones de bean compatibles con el tipo de una propiedad o argumento de constructor. En arrays, colecciones y mapas esto no suele ser un problema; pero, cuando se espera un único valor, Spring no resuelve la ambigüedad arbitrariamente y lanza una excepción.

Ante una ambigüedad, puedes:

  • Sustituir la autoconexión por una conexión explícita.
  • Excluir un bean como candidato de autoconexión.
  • Marcar un bean como candidato principal.
  • Usar el control más detallado de la configuración basada en anotaciones.

Excluir un bean de la autoconexión

Puedes excluir un bean individual de la autoconexión.

En XML, establece autowire-candidate="false":

<bean id="auditRepository"
      class="com.example.AuditRepository"
      autowire-candidate="false"/>

En una configuración Java con @Bean, el atributo equivalente es autowireCandidate:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean(autowireCandidate = false)
    AuditRepository auditRepository() {
        return new AuditRepository();
    }
}

El contenedor deja ese bean fuera de la infraestructura de autoconexión, incluidas las inyecciones basadas en anotaciones, como @Autowired.

La exclusión solo afecta a la autoconexión basada en tipo. No impide las referencias explícitas por nombre: si una referencia nombra directamente ese bean, Spring podrá resolverla. Por ello, la autoconexión por nombre todavía puede inyectar un bean excluido cuando el nombre coincide.

También puedes limitar los candidatos mediante patrones de nombres en el elemento raíz <beans/>. Por ejemplo, el siguiente ajuste permite que solo los beans cuyo nombre termine en Repository sean candidatos predeterminados:

<beans default-autowire-candidates="*Repository">
    <!-- definiciones de beans -->
</beans>

Para varios patrones, sepáralos con comas. Un valor explícito de true o false en autowire-candidate para un bean siempre tiene prioridad sobre las reglas de coincidencia de patrones.