Spring proporciona una forma de detectar automáticamente las relaciones entre varios beans. Esto se puede hacer declarando todas las dependencias del bean en el archivo de configuración de Spring. Por lo tanto, Spring puede utilizar BeanFactory para conocer las dependencias de todos los beans utilizados.

La funcionalidad de autowiring basada en la configuración XML tiene cinco modos: no, byName, byType, constructor y autodetect. El modo predeterminado es no.

Modos de @Autowire

  • no: es el modo autowire predeterminado. Significa que no hay autowiring.
  • byName: el modo byName inyecta la dependencia del objeto de acuerdo con el nombre del bean. En tal caso, la propiedad y el nombre del bean deberían ser los mismos. Llama internamente al método setter.
  • byType: el modo byType inyecta la dependencia del objeto según el tipo. Por lo tanto, puede tener una propiedad y un nombre de bean diferentes. Llama internamente al método setter.
  • constructor: el modo constructor inyecta la dependencia llamando al constructor de la clase. Llama al constructor que tiene una gran cantidad de parámetros.
  • autodetect: en este modo, Spring primero intenta autowire por el constructor. Si esto falla, intenta conectarse automáticamente mediante byType.

En versiones mas primitivas configurabamos estas propiedades por medio de archivos xml, y teníamos que satisfacer las dependencias de cada bean a través del un setter.

A modo de museo, y como referencia para proyectos legacy, dejo un ejemplo de cada uno.

Autowiring: no

<bean id="departamento" class="com.ricardogeek.Departamento">
  <property name="nombreDepto" value="IT" />
</bean>
<bean id="empleado" class="com.ricardogeek.Empleado"></bean>

Autowiring: byName

<bean id="department" class="com.ricardogeek.Department">
    <property name="nombreDepto" value="IT" />
</bean>

<bean id="empleado" class="com.ricardogeek.Empleado" autowire="byName"></bean>

Autowiring: byType

<bean id="department" class="com.ricardogeek.Department">
    <property name="nombreDepto" value="IT" />
</bean>

<bean id="empleado" class="com.ricardogeek.Empleado" autowire="byType"></bean>

Autowiring: constructor

<bean id="department" class="com.ricardogeek.Department">
    <property name="nombreDepto" value="IT" />
</bean>

<bean id="empleado" class="com.ricardogeek.Empleado" autowire="constructor"></bean>

Autowiring: autodetect

<bean id="department" class="com.ricardogeek.Department">
    <property name="nombreDepto" value="IT" />
</bean>

<bean id="empleado" class="com.ricardogeek.Empleado" autowire="autodetect"></bean>

Ejemplo de autowiring

Siendo que tenemos las configuraciones anteriores, ahora creamos los objetos que configuramos:

public class Departamento {
    private String nombreDepto;

    public String getNombreDepto() {
        return nombreDepto;
    }

    public void setNombreDepto(final String nombreDepto) {
        this.nombreDepto = nombreDepto;
    }
}

Y ahora para la clase Empleado

public class Empleado {

    private int id;
    private String nombre;
    private Departamento departmento;

    public int getId() {
        return id;
    }

    public void setId(final int id) {
        this.id = id;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(final String nombre) {
        this.nombre = nombre;
    }

    public Departamento getDepartmento() {
        return departmento;
    }

    public void setDepartmento(final Departamento departmento) {
        this.departmento = departmento;
    }

    public void printEmpleado(){
        System.out.println("Id : " + id);
        System.out.println("Nombre : " + ename);
        System.out.println("Departmento : " + departmento.getNombreDepto());
    }
}

Y ahora agregamos la configuración XML (mas adelante vemos como nos ahorramos este bochorno)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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.xsd  http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">
   <bean id="department" class="com.ricardogeek.Departmento">
      <property name="deptName" value="IT" />
   </bean>
   <bean id="empleado" class="com.ricardogeek.Empleado" autowire="byName" />
</beans>

Ahora para correr la aplicación definimos la clase principal:

@SpringBootApplication
public class EjemploAutowire {

    public static void main(String[] args) {
        SpringApplication.run(AutowiringdemoApplication.class, args);
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        Empleado emp = context.getBean("empleado", Empleado.class);
        emp.setId(101);
        emp.setName("RicardoGeek");
        emp.printEmpleado();
    }

}

Y al correr la aplicación obtenemos lo siguiente:

Id: 101
Nombre: RicardoGeek
Departmento: IT

Process finished with exit code 0

Anotación @Autowired

La anotación @Autowired, funciona a nivel de clase tanto como a nivel de método y de propiedad. y podemos configurarla de la siguiente manera:

@Configuration
@ComponentScan("com.ricardogeek.EjemploAutowire")
public class AppConfig {}

O bien siempre usar un archivo XML pero mas simple con el siguiente conteido:

<context:annotation-config />

Ahora digamos que queremos obtener un bean que ya esta dentro del contexto de la aplicación sin tener que escribir una sola linea extra de código XML, simplemente hay que marcar lo que queremos obtener con la anotación @Component:

import org.springframework.stereotype.Component;

@Component
public class Departmento {

    private String nombreDepto;

    public String getNombreDepto() {
        return nombreDepto;
    }

    public void setNombreDepto(String nombreDepto) {
        this.nombreDepto = nombreDepto;
    }
}

Y luego, después de asegurarnos que se encuentra dentro del paquete o paquetes que marcamos como component scan, podemos usarlo fácilmente como sigue:

public class Empleado {

    private int id;
    private String nombre;
    @Autowired
    private Departamento departmento;

    public int getId() {
        return id;
    }

    public void setId(final int id) {
        this.id = id;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(final String nombre) {
        this.nombre = nombre;
    }

    public Departamento getDepartmento() {
        return departmento;
    }

    public void setDepartmento(final Departamento departmento) {
        this.departmento = departmento;
    }

    public void printEmpleado(){
        System.out.println("Id : " + id);
        System.out.println("Nombre : " + ename);
        System.out.println("Departmento : " + departmento.getNombreDepto());
    }
}

Note que ahora la propiedad Departamento contiene la anotación @Autowired, esto hace que la dependencia sea inyectada sin necesidad de un setter.

Y finalmente podemos inyectar una dependencia como parámetro de un método automáticamente marcándolo con @Autowired

@Component
public class Empleado {

    private int id;
    private String nombre;
    private Departamento departmento;

    public int getId() {
        return id;
    }

    public void setId(final int id) {
        this.id = id;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(final String nombre) {
        this.nombre = nombre;
    }

    public Departamento getDepartmento() {
        return departmento;
    }

    @Autowired
    public void setDepartmento(final Departamento departmento) {
        this.departmento = departmento;
    }

    public void printEmpleado(){
        System.out.println("Id : " + id);
        System.out.println("Nombre : " + ename);
        System.out.println("Departmento : " + departmento.getNombreDepto());
    }
}

Aquí en el setter setDepartamento spring intentará inyectar todas las dependencias que encuentre en el actual contexto de la aplicación.

De igual manera, funcionaría si pusiéramos esto en un constructor.

Si no se encuentra ningún bean para efectuar el @Autowired, nos saltara una excepción indicando cual o cuales son exactamente los beans que nos hacen falta para satisfacer la anotación. Y basta con colocarlos como @Component bajo los paquetes en el ComponentScan.

Y recuerden, los archivos XML no siempre son malos. Tienen la ventaja de que si es viernes y encontraron un bug en producción, los archivos xml de contexto de aplicación pueden ser “hot fixed” sin necesidad de esperar un nuevo build. Si lo hacen, no olviden versionar el hotfix.

Categorized in:

Tagged in:

, ,