Spring Boot

SpringBoot

Tutorial SpringBoot: Inyección de dependencias

Spring Boot inyección de dependencias: uso. Domina la inyección de dependencias en Spring Boot con ejemplos prácticos y detallados.

La Inyección de Dependencias (DI) es un patrón de diseño de software que permite eliminar las dependencias estáticas entre el código y hacer que las aplicaciones sean más fáciles de probar y mantener.

Spring Boot es una herramienta que utiliza la DI como un componente central para desarrollar aplicaciones.

Inversión de Control

La Inversión de Control (IoC) es un principio de diseño de software en el cual el flujo de control de un programa se "invierte", es decir, el programa delega el control de las funciones a cualquier módulo o servicio asociativo que lo necesite. Esto significa que en lugar de que el programa llame a las funciones cuando las necesita, son las funciones las que llaman al programa cuando están listas para ser ejecutadas. En el contexto de Spring Boot, el marco de trabajo se hace cargo de la creación de objetos y la gestión de su ciclo de vida, que es la esencia del contenedor IoC.

El contenedor IoC de Spring es el núcleo del marco de trabajo de Spring que se encarga de la creación de objetos, configuración y ensamblado de los mismos. El contenedor IoC facilita la ID y permite que los objetos se configuren y se enlacen de manera declarativa.

Inyección de Dependencias

La ID es un patrón de diseño que implementa el principio de Inversión de Control. En lugar de que los objetos configuren sus propias dependencias, estas son pasadas al objeto por un controlador externo. En términos simples, las dependencias de un objeto son inyectadas por otro objeto. La ID ayuda a separar el comportamiento de un objeto de sus dependencias, lo que facilita la prueba y el mantenimiento del código.

En Spring Boot, existen tres tipos de ID: constructor, setter y field.

Inyección de Dependencias por Constructor

La Inyección de Dependencias por Constructor (Constructor Injection, en inglés) es una técnica en la que el contenedor de Spring inyecta las dependencias de un objeto a través de los argumentos del constructor de ese objeto.

Este método de inyección de dependencias es generalmente preferido y recomendado por los desarrolladores de Spring por varias razones, entre ellas:

Inmutabilidad: Los objetos inyectados a través del constructor pueden ser marcados como final, garantizando la inmutabilidad de la dependencia, es decir, una vez que la dependencia es establecida, no puede ser modificada. Esto es útil para garantizar que las dependencias no sean cambiadas inadvertidamente después de la creación del objeto.

Prevención de NullPointerException: Como las dependencias son inyectadas en el momento de la creación del objeto, esto garantiza que el objeto tenga todas sus dependencias necesarias antes de que se le permita realizar cualquier otro procesamiento, ayudando a prevenir posibles NullPointerException.

Orden de las dependencias: Con la inyección de dependencias por constructor, se puede controlar el orden de inicialización de las dependencias.

A continuación se muestra un ejemplo detallado de cómo se realiza la inyección de dependencias por constructor:

package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class TrabajoService {
    public void realizarTrabajo() {
        System.out.println("Trabajo realizado.");
    }
}
package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class EmpleadoService {

    private final TrabajoService trabajoService;
    
    public EmpleadoService(TrabajoService trabajoService) {
        this.trabajoService = trabajoService;
    }

    public void iniciarTrabajo() {
        trabajoService.realizarTrabajo();
    }
}

Aquí se aprecia el uso de la inyección de dependencias por constructor en Spring Boot.

El servicio EmpleadoService depende del servicio TrabajoService, y este último es inyectado automáticamente por Spring Boot en el constructor.

Así, la inyección de dependencias por constructor permite una gestión de dependencias limpia y segura en aplicaciones Spring Boot.

A partir de Spring 4.3, la anotación @Autowired es opcional si la clase objetivo solo tiene un constructor. El contenedor de Spring puede inferir que el constructor se debe usar para la inyección de dependencias. Por tanto para este ejemplo no es necesario el uso de @Autowired.

Inyección de Dependencias por Setter

La inyección de dependencias por método setter es una forma en la que Spring Boot facilita la inyección de dependencias en una aplicación. En este enfoque, las dependencias se inyectan a través de métodos setter en la clase dependiente.

La inyección por setter puede ser útil cuando se tiene una dependencia opcional, es decir, un objeto que puede funcionar correctamente incluso si la dependencia no está presente o no se ha inicializado. Con la inyección de dependencias por setter, el objeto se puede crear y utilizar, y la dependencia se puede establecer más tarde utilizando el método setter.

A continuación se muestra un ejemplo de cómo se realiza la inyección de dependencias por setter:

En un archivo TrabajoService.java:

package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class TrabajoService {
    public void realizarTrabajo() {
        System.out.println("Trabajo realizado.");
    }
}

En otro archivo EmpleadoService.java:

package com.example.demo.service;

import org.springframework.stereotype.Service;

@Service
public class EmpleadoService {

    private TrabajoService trabajoService;
    
    public void setTrabajoService(TrabajoService trabajoService) {
        this.trabajoService = trabajoService;
    }

    public void iniciarTrabajo() {
        if (trabajoService != null) {
            trabajoService.realizarTrabajo();
        }
    }
}

En este ejemplo, TrabajoService se inyecta en EmpleadoService usando un método setter (setTrabajoService). 

La anotación @Autowired es opcional en Spring 4.3 y versiones posteriores si tienes solo un método setter en tu clase.

El método iniciarTrabajo() verifica si trabajoService es null antes de intentar utilizarlo. Esto es útil si consideras que TrabajoService podría no estar disponible por alguna razón, aunque en un escenario típico de Spring Boot, si la dependencia no está disponible, la aplicación no arrancará.

Aunque la inyección de dependencias por setter puede ser útil en algunos casos, también puede hacer que el código sea más difícil de seguir y probar, y puede dar lugar a objetos en estados inválidos o inesperados. Por esta razón, generalmente se recomienda la inyección de dependencias por constructor, que garantiza que todas las dependencias necesarias se inyecten en el momento de la creación del objeto.

Inyección de Dependencias por Field

La Inyección de Dependencias por campo o Field (Field Injection, en inglés) es una técnica en la que el marco de trabajo de Spring inyecta las dependencias directamente en los campos de una clase. Esto se realiza utilizando la anotación @Autowired en el campo donde se desea que Spring inyecte la dependencia.

La inyección de dependencias por field puede resultar más fácil y rápida de implementar, ya que no requiere la escritura de métodos setter ni constructores para las dependencias. Sin embargo, tiene algunas desventajas, entre las cuales destacan:

Rompe la encapsulación: Al inyectar directamente en los campos, se rompe la encapsulación ya que la dependencia no se inyecta a través de setters o constructores.

Dificulta las pruebas: En las pruebas unitarias, no se puede inyectar las dependencias de manera manual como se podría hacer si se inyectaran a través de setters o constructores.

A continuación se muestra un ejemplo de cómo se realiza la inyección de dependencias por field:

@Service
public class EmpleadoService {

  @Autowired
  private TrabajoService trabajoService;

  public void iniciarTrabajo() {
      trabajoService.realizarTrabajo();
  }
}

En este ejemplo, TrabajoService es una dependencia de la clase EmpleadoService. La anotación @Autowired sobre el campo trabajoService indica a Spring que debe inyectar un objeto de tipo TrabajoService directamente en ese campo.

El método iniciarTrabajo() luego utiliza esta dependencia inyectada para llamar al método realizarTrabajo().

Aunque la inyección de dependencias por campo puede ser conveniente en algunos casos, generalmente es recomendable utilizar la inyección de dependencias por constructor o por setter para mantener una buena encapsulación y facilitar las pruebas.

Autowiring

El Autowiring es una característica específica de Spring que permite a la biblioteca manejar automáticamente la inyección de dependencias.

Cuando Spring crea los beans, examina las anotaciones (como @Autowired, @Resource, @Inject, etc.) para decidir qué otros beans necesitan ser inyectados.

Para utilizar Autowiring, se marca la dependencia con la anotación @Autowired. Spring entonces buscará en su contenedor de IoC un bean que coincida con el tipo de la dependencia y lo inyectará automáticamente.

⚠️ CUIDADO: Si Spring no puede encontrar un bean que coincida con la dependencia o si hay más de un bean del mismo tipo, se lanzará una excepción.

A continuación, se presenta un ejemplo de Autowiring en un campo:

@Service
public class Empleado {

  @Autowired
  private Departamento departamento;

  public void iniciarTrabajo() {
    departamento.realizarTrabajo();
  }
}

En este ejemplo, el campo departamento está marcado con la anotación @Autowired, por lo que Spring inyectará automáticamente un bean de tipo Departamento.

Si se desea que Spring no lance una excepción cuando no puede encontrar un bean correspondiente, se puede establecer el parámetro required de la anotación @Autowired en false:

@Autowired(required = false)
private Departamento departamento;

Con required = false, Spring inyectará la dependencia si puede encontrar un bean correspondiente; si no, establecerá la dependencia en null.

Además, el comportamiento de @Autowired puede modificarse utilizando la anotación @Qualifier, que permite especificar cuál de los beans que coinciden se debe inyectar cuando hay más de uno que podría coincidir.

Para los casos en los que se configura Spring a través de XML, se puede especificar el modo de autowiring para un bean utilizando el atributo autowire en la definición del bean. Hay cuatro opciones para este atributo: no, byName, byType y constructor.

  • no: Este es el valor predeterminado. No se realiza autowiring. Las dependencias deben inyectarse explícitamente mediante referencias de bean.
  • byName: Spring busca en el contenedor un bean cuyo nombre coincida con el nombre del campo o de la propiedad (setter) que necesita la inyección.
  • byType: Spring busca en el contenedor un bean que sea del mismo tipo que el campo o la propiedad (setter) que necesita la inyección. Si encuentra más de uno, lanza una excepción.
  • constructor: Similar a byType, pero se aplica al constructor de un bean en lugar de a un setter o a un campo. Si hay más de un constructor que puede utilizarse, Spring usa el que tiene más argumentos.

Hay que tener en cuenta que los modos byName, byType y constructor están en desuso en las versiones más recientes de Spring a favor de usar @Autowired junto con @Qualifier si es necesario.

Los modos de autowiring byName y byType también se pueden utilizar con anotaciones en lugar de XML. Aquí tienes un ejemplo con @Autowired y @Qualifier:

public class Empleado {

  private Departamento departamento;

  @Autowired
  public void setDepartamento(@Qualifier("miDepartamento") Departamento departamento) {
    this.departamento = departamento;
  }

  public void iniciarTrabajo() {
    departamento.realizarTrabajo();
  }
}

En este ejemplo, se usa @Qualifier para especificar el bean que se debe inyectar cuando hay más de un bean de tipo Departamento en el contenedor de Spring.

En general, Autowiring es una forma conveniente de gestionar las dependencias en Spring, pero también puede hacer que el código sea más difícil de seguir y probar, especialmente si se utiliza la inyección de dependencias por campo. 

Por lo tanto, se recomienda generalmente utilizar Autowiring con la inyección de dependencias por constructor, que facilita la prueba y el seguimiento de las dependencias.

Certifícate en SpringBoot con CertiDevs PLUS

Ejercicios de esta lección Inyección de dependencias

Evalúa tus conocimientos de esta lección Inyección de dependencias con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Web y Test Starters

Spring Boot
Puzzle

Entidades JPA

Spring Boot
Test

Repositorios reactivos

Spring Boot
Test

Inserción de datos

Spring Boot
Test

Borrar datos de base de datos

Spring Boot
Test

Controladores Spring MVC

Spring Boot
Código

Backend API REST con Spring Boot

Spring Boot
Proyecto

Operadores Reactivos

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Código

Uso de Spring con Thymeleaf

Spring Boot
Puzzle

Crear entidades JPA

Spring Boot
Código

Registro de usuarios

Spring Boot
Test

CRUD y JPA Repository

Spring Boot
Puzzle

Anotaciones y mapeo en JPA

Spring Boot
Puzzle

Integración con Vue

Spring Boot
Test

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Test

Open API y cómo agregarlo en Spring Boot

Spring Boot
Puzzle

Uso de Controladores REST

Spring Boot
Puzzle

API Specification

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Test

Introducción a Spring Boot

Spring Boot
Test

Consultas JPQL con @Query en Spring Data JPA

Spring Boot
Puzzle

API Query By Example (QBE)

Spring Boot
Puzzle

Inyección de dependencias

Spring Boot
Código

Vista en Spring MVC con Thymeleaf

Spring Boot
Test

Servicios en Spring

Spring Boot
Código

Configuración de Vue

Spring Boot
Puzzle

Integración con Angular

Spring Boot
Test

API Query By Example (QBE)

Spring Boot
Test

API Specification

Spring Boot
Test

Controladores MVC

Spring Boot
Test

Métodos find en repositorios

Spring Boot
Test

Repositorios Spring Data

Spring Boot
Test

Inyección de dependencias

Spring Boot
Puzzle

Data JPA y Mail Starters

Spring Boot
Test

Configuración de Angular

Spring Boot
Puzzle

Controladores Spring REST

Spring Boot
Test

Configuración de Controladores MVC

Spring Boot
Puzzle

Asociaciones de entidades JPA

Spring Boot
Código

Actualizar datos de base de datos

Spring Boot
Test

Identificadores y relaciones JPA

Spring Boot
Puzzle

Verificar token JWT en peticiones

Spring Boot
Test

Login de usuarios

Spring Boot
Test

Integración con React

Spring Boot
Test

Configuración de React

Spring Boot
Puzzle

Asociaciones en JPA

Spring Boot
Test

Consultas JPQL

Spring Boot
Código

Todas las lecciones de SpringBoot

Accede a todas las lecciones de SpringBoot y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Spring Boot

Spring Boot

Introducción Y Entorno

Spring Boot Starters

Spring Boot

Introducción Y Entorno

Inyección De Dependencias

Spring Boot

Introducción Y Entorno

Controladores Spring Mvc

Spring Boot

Spring Web

Vista En Spring Mvc Con Thymeleaf

Spring Boot

Spring Web

Controladores Spring Rest

Spring Boot

Spring Web

Open Api Y Cómo Agregarlo En Spring Boot

Spring Boot

Spring Web

Servicios En Spring

Spring Boot

Spring Web

Crear Entidades Jpa

Spring Boot

Persistencia Con Spring Data

Asociaciones De Entidades Jpa

Spring Boot

Persistencia Con Spring Data

Repositorios Spring Data

Spring Boot

Persistencia Con Spring Data

Métodos Find En Repositorios

Spring Boot

Persistencia Con Spring Data

Inserción De Datos

Spring Boot

Persistencia Con Spring Data

Actualizar Datos De Base De Datos

Spring Boot

Persistencia Con Spring Data

Borrar Datos De Base De Datos

Spring Boot

Persistencia Con Spring Data

Consultas Jpql Con @Query En Spring Data Jpa

Spring Boot

Persistencia Con Spring Data

Api Query By Example (Qbe)

Spring Boot

Persistencia Con Spring Data

Repositorios Reactivos

Spring Boot

Persistencia Con Spring Data

Api Specification

Spring Boot

Persistencia Con Spring Data

Integración Con React

Spring Boot

Integración Frontend

Integración Con Vue

Spring Boot

Integración Frontend

Integración Con Angular

Spring Boot

Integración Frontend

Registro De Usuarios

Spring Boot

Seguridad Con Spring Security

Login De Usuarios

Spring Boot

Seguridad Con Spring Security

Verificar Token Jwt En Peticiones

Spring Boot

Seguridad Con Spring Security

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el concepto y el propósito de la Inversión de Control (IoC) y cómo se implementa en Spring Boot.
  2. Aprender sobre la inyección de dependencias, incluyendo la inyección por constructor, setter y field.
  3. Entender cómo funciona Autowiring en Spring Boot y cómo se pueden usar las anotaciones @Autowired y @Qualifier para automatizar y personalizar la inyección de dependencias.
  4. Aprender a manejar situaciones en las que hay múltiples beans de un mismo tipo y cómo Spring resuelve las ambigüedades.
  5. Familiarizarse con los distintos modos de Autowiring en Spring: no, byName, byType, constructor.