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.
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
Entidades JPA
Repositorios reactivos
Inserción de datos
Borrar datos de base de datos
Controladores Spring MVC
Backend API REST con Spring Boot
Operadores Reactivos
Controladores Spring REST
Uso de Spring con Thymeleaf
Crear entidades JPA
Registro de usuarios
CRUD y JPA Repository
Anotaciones y mapeo en JPA
Integración con Vue
Consultas JPQL con @Query en Spring Data JPA
Open API y cómo agregarlo en Spring Boot
Uso de Controladores REST
API Specification
Inyección de dependencias
Introducción a Spring Boot
Consultas JPQL con @Query en Spring Data JPA
API Query By Example (QBE)
Inyección de dependencias
Vista en Spring MVC con Thymeleaf
Servicios en Spring
Configuración de Vue
Integración con Angular
API Query By Example (QBE)
API Specification
Controladores MVC
Métodos find en repositorios
Repositorios Spring Data
Inyección de dependencias
Data JPA y Mail Starters
Configuración de Angular
Controladores Spring REST
Configuración de Controladores MVC
Asociaciones de entidades JPA
Actualizar datos de base de datos
Identificadores y relaciones JPA
Verificar token JWT en peticiones
Login de usuarios
Integración con React
Configuración de React
Asociaciones en JPA
Consultas JPQL
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
Introducción Y Entorno
Spring Boot Starters
Introducción Y Entorno
Inyección De Dependencias
Introducción Y Entorno
Controladores Spring Mvc
Spring Web
Vista En Spring Mvc Con Thymeleaf
Spring Web
Controladores Spring Rest
Spring Web
Open Api Y Cómo Agregarlo En Spring Boot
Spring Web
Servicios En Spring
Spring Web
Crear Entidades Jpa
Persistencia Con Spring Data
Asociaciones De Entidades Jpa
Persistencia Con Spring Data
Repositorios Spring Data
Persistencia Con Spring Data
Métodos Find En Repositorios
Persistencia Con Spring Data
Inserción De Datos
Persistencia Con Spring Data
Actualizar Datos De Base De Datos
Persistencia Con Spring Data
Borrar Datos De Base De Datos
Persistencia Con Spring Data
Consultas Jpql Con @Query En Spring Data Jpa
Persistencia Con Spring Data
Api Query By Example (Qbe)
Persistencia Con Spring Data
Repositorios Reactivos
Persistencia Con Spring Data
Api Specification
Persistencia Con Spring Data
Integración Con React
Integración Frontend
Integración Con Vue
Integración Frontend
Integración Con Angular
Integración Frontend
Registro De Usuarios
Seguridad Con Spring Security
Login De Usuarios
Seguridad Con Spring Security
Verificar Token Jwt En Peticiones
Seguridad Con Spring Security
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender el concepto y el propósito de la Inversión de Control (IoC) y cómo se implementa en Spring Boot.
- Aprender sobre la inyección de dependencias, incluyendo la inyección por constructor, setter y field.
- 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. - Aprender a manejar situaciones en las que hay múltiples beans de un mismo tipo y cómo Spring resuelve las ambigüedades.
- Familiarizarse con los distintos modos de Autowiring en Spring:
no
,byName
,byType
,constructor
.