Dominar la inyección de dependencias es fundamental para construir aplicaciones modulares y escalables con Spring Boot. Aquí se explica paso a paso cómo crear una dependencia propia usando el estereotipo @Component, cómo inyectarla en otras clases del proyecto y qué hacer cuando existen múltiples implementaciones de una misma interfaz.
¿Cómo se crea una dependencia con @Component?
El punto de partida es definir una interfaz que represente el contrato de la dependencia. En este caso se crea una interfaz llamada ComponentDependencia con un método saludar [0:37]:
java
public interface ComponentDependencia {
void saludar();
}
Después se crea la clase ComponentImplement, que implementa esa interfaz y se anota con @Component [1:07]. Esta anotación le indica a Spring Boot que la clase es un componente gestionado por el contenedor de inversión de control (IoC container), es decir, Spring se encargará de instanciarla y administrar su ciclo de vida.
java
@Component
public class ComponentImplement implements ComponentDependencia {
@Override
public void saludar() {
System.out.println("Hola, mundo, desde mi componente");
}
}
¿Cómo se inyecta la dependencia en otra clase?
Para utilizar la dependencia se recurre a la inyección por constructor. En la clase principal FundamentosApplication se declara una propiedad del tipo de la interfaz —no de la implementación concreta— y se recibe como parámetro del constructor [1:24]:
java
private ComponentDependencia componentDependency;
public FundamentosApplication(ComponentDependencia componentDependency) {
this.componentDependency = componentDependency;
}
Un dato relevante es que en versiones recientes de Spring Boot ya no es obligatorio agregar la anotación @Autowired sobre el constructor cuando la clase tiene un único constructor [1:55]. Spring lo detecta automáticamente.
¿Qué papel cumple CommandLineRunner?
Para ejecutar código al iniciar la aplicación se implementa la interfaz CommandLineRunner y su método run [2:07]. Dentro de ese método se invoca el servicio inyectado:
java
@Override
public void run(String... args) {
componentDependency.saludar();
}
Al compilar y ejecutar el proyecto, la consola muestra el mensaje "Hola, mundo, desde mi componente", confirmando que la dependencia fue inyectada y utilizada correctamente [2:30].
¿Qué ocurre con múltiples implementaciones de una interfaz?
Si se crea una segunda clase, por ejemplo ComponentTwoImplement, que también implementa ComponentDependencia y se anota con @Component, Spring Boot lanza un error de ambigüedad [3:07]. El framework no sabe cuál de las dos implementaciones debe inyectar.
¿Cómo resolver la ambigüedad con @Qualifier?
La solución es la anotación @Qualifier, que permite especificar exactamente qué implementación se desea utilizar [3:28]. El valor que recibe es el nombre de la clase con la primera letra en minúscula (convención de Spring para los nombres de beans):
java
public FundamentosApplication(
@Qualifier("componentTwoImplement") ComponentDependencia componentDependency) {
this.componentDependency = componentDependency;
}
Al ejecutar de nuevo, el resultado es "Hola, mundo, desde mi Component dos" [3:53], confirmando que se inyectó la segunda implementación.
Esta combinación de @Component y @Qualifier permite tener "n" implementaciones de una sola interfaz y elegir en cada punto de inyección cuál usar. Algunos aspectos clave a recordar:
- Segregar por interfaz: siempre se inyecta el tipo de la interfaz, no el de la clase concreta.
- Un constructor, sin @Autowired: Spring Boot moderno lo resuelve solo.
- @Qualifier para desambiguar: indispensable cuando hay más de una implementación anotada como componente.
Si ya lograste crear e inyectar tu primera dependencia, el siguiente paso es aprender a hacerlo sin utilizar ningún estereotipo, lo que abre aún más posibilidades de configuración. ¿Tienes dudas sobre cómo funciona el contenedor de Spring? Comparte tu experiencia en los comentarios.