Cualquiera que haya trabajado al menos una vez con la inyección de dependencias en un proyecto real sabe: los errores son inevitables. Así que vamos a ver de antemano qué errores al inyectar dependencias nos vamos a encontrar con más frecuencia.
Antes de empezar a revisar los "meteduras de pata" concretos y cómo solucionarlos, respondamos a la pregunta: ¿por qué es tan importante hablar de los errores?
Los errores en la inyección de dependencias no son simplemente molestias menores. Pueden provocar la caída de la aplicación, el mal funcionamiento de los beans o fallos globales en sistemas a gran escala. Además, como se dice, depurar código es como una investigación detectivesca. Si ya sabemos qué buscar, la vida es mucho más sencilla.
1. Errores típicos en DI y cómo evitarlos
1. Falta de un bean en el contexto
El error más común. Declaras una dependencia con @Autowired, y en algún rincón oscuro de tu aplicación Spring no encuentra el bean para esa dependencia.
Síntomas: un error del tipo:
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type '<your.bean.Class>' available
Causa: el bean de la clase o interfaz necesaria simplemente no está registrado en el contexto de Spring. Puede ocurrir si olvidaste anotar la clase, por ejemplo, con @Component o no registraste el bean mediante @Bean.
Solución:
- Asegúrate de que tu clase esté marcada como
@Component,@Service,@Repositoryo se cree en la configuración mediante@Bean. - Verifica que tu bean esté en un paquete que Spring escanee. Si usas un
@ComponentScanpersonalizado, añade el paquete necesario. - Por si acaso, comprueba que las clases se importen correctamente (sí, banal, pero pasa).
@Component // Sin esta anotación el bean no se creará
public class MyService {
// Código
}
2. Beans ambiguos (Bean Ambiguity)
Registras varios beans del mismo tipo, pero Spring no sabe cuál usar.
Síntomas: un error del tipo:
org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type '<your.bean.Class>' available:
expected single matching bean but found 2
Causa: tienes varios beans del mismo tipo y Spring no puede leer tu mente.
Solución: usa la anotación @Qualifier para indicarle a Spring cuál bean usar.
@Component("bean1")
public class MyBean1 {
// Código
}
@Component("bean2")
public class MyBean2 {
// Código
}
@Service
public class MyService {
private final MyBean1 bean;
@Autowired
public MyService(@Qualifier("bean1") MyBean1 bean) {
this.bean = bean;
}
}
3. Dependencias cíclicas
Síntomas: la aplicación no arranca, y en los logs ves algo intimidante, más o menos así:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name '<beanName>':
Requested bean is currently in creation: Is there an unresolvable circular reference?
Causa: dos (o más) clases dependen una de la otra. Por ejemplo:
@Component
public class ClassA {
@Autowired
private ClassB classB;
}
@Component
public class ClassB {
@Autowired
private ClassA classA;
}
Spring se queda atascado en un intento infinito de inicializar las clases.
Solución:
- Revisa las dependencias. Normalmente las dependencias cíclicas indican problemas en el diseño de la aplicación.
- Si la dependencia cíclica es inevitable:
- Usa
@Lazyal inyectar una de las dependencias, para que Spring la cree solo cuando se necesite.
- Usa
@Component
public class ClassA {
@Autowired
@Lazy
private ClassB classB;
}
4. Error al autoconectar colecciones
Quieres inyectar una lista de beans, pero algo salió mal.
Síntomas: error del tipo:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [List<YourType>] found
Causa: Spring no sabe cómo construir la colección de beans.
Solución: para inyectar colecciones usa @Autowired en el constructor, setter o campo, y especifica el tipo como List o Map.
@Component
public class MyService {
private final List<MyInterface> beans;
@Autowired
public MyService(List<MyInterface> beans) {
this.beans = beans;
}
}
Todos los beans que implementen MyInterface se añadirán automáticamente a la lista.
5. Scope incorrecto
Síntomas:
- El comportamiento de la aplicación es raro. Por ejemplo, un bean que debería ser singleton de repente se crea varias veces.
- O, al contrario, un bean con scope prototype "se comporta" como singleton (clásico).
Causa: o bien asignaste el scope incorrecto, o no entiendes bien cómo funciona el scope elegido.
Solución: asegúrate de que el scope esté indicado correctamente. Para Singleton:
@Component
@Scope("singleton")
public class SingletonBean {
// Código
}
Para Prototype:
@Component
@Scope("prototype")
public class PrototypeBean {
// Código
}
2. Consejos prácticos para depurar errores de DI
Logs de Spring: habilita el logging en nivel DEBUG para el paquete de Spring. Muchas veces en los logs hay pistas útiles.
logging.level.org.springframework=DEBUG
Comprobación del contexto: puedes solicitar todos los beans del contexto y ver cuáles están disponibles:
@Autowired
private ApplicationContext context;
public void printAllBeans() {
for (String beanName : context.getBeanDefinitionNames()) {
System.out.println(beanName);
}
}
Separa responsabilidades: si hay demasiadas dependencias, piensa en descomponer tu código. Eso puede eliminar problemas complejos con los beans.
Error en los tipos de inyección: si un bean fue creado para una interfaz, hay que tener especial cuidado. Asegúrate de que el tipo inyectado esté bien resuelto.
3. Checklist por si hay un problema con DI
- Revisar las anotaciones (
@Component,@Service,@Repository,@Configuration,@Bean). - Asegurarse de que la clase esté en el area escaneada (
@ComponentScano su equivalente). - Comprobar si hay beans ambiguos. Si los hay, usar
@Qualifier. - Buscar dependencias cíclicas. Si existen, usar
@Lazyo revisar el diseño. - Analizar los logs de Spring para obtener información detallada sobre los errores.
Ahora tienes un conjunto potente de herramientas para luchar contra los errores en la inyección de dependencias. Con estos conocimientos, trabajar con DI será mucho más agradable.
GO TO FULL VERSION