Spring NoSuchBeanDefinitionException

1. Vue d'ensemble

Dans cet article, nous discutons de l' exception Spring org.springframework.beans.factory.NoSuchBeanDefinitionException - il s'agit d'une exception courante lancée par BeanFactory lorsque vous essayez de résoudre un bean qui n'est tout simplement pas défini dans le contexte Spring.

Nous illustrerons les causes possibles de ce problème et les solutions disponibles.

Et bien sûr, les exceptions se produisent lorsque vous vous y attendez le moins; Jetez un œil à la liste complète des exceptions et des solutions au printemps.

2. Cause: aucun bean éligible de type […] trouvé pour la dépendance

La cause la plus courante de cette exception est simplement d'essayer d'injecter un bean qui n'est pas défini. Par exemple - BeanB est en train de câbler un collaborateur - BeanA:

@Component public class BeanA { @Autowired private BeanB dependency; //... }

Maintenant, si la dépendance - BeanB - n'est pas définie dans le contexte Spring, le processus d'amorçage échouera sans l'exception de définition de bean :

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.BeanB] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

La raison est clairement indiquée par Spring: " attendu au moins 1 bean qui se qualifie comme candidat autowire pour cette dépendance "

Une des raisons pour lesquelles BeanB peut ne pas exister dans le contexte - si les beans sont automatiquement captés par l' analyse du chemin de classe , et si BeanB est correctement annoté en tant que bean ( @Component , @Repository , @Service , @Controller , etc.) - est qu'il peut être défini dans un package qui n'est pas analysé par Spring :

package com.baeldung.packageB; @Component public class BeanB { ...}

Alors que l'analyse du chemin de classe peut être configurée comme suit:

@Configuration @ComponentScan("com.baeldung.packageA") public class ContextWithJavaConfig { ... }

Si les beans ne sont pas automatiquement analysés par à la place définis manuellement , alors BeanB n'est tout simplement pas défini dans le contexte Spring actuel.

3. Cause: Le champ […] de […] nécessitait un bean de type […] introuvable

Dans une application Spring Boot pour le scénario ci-dessus, nous obtenons un message différent.

Prenons le même exemple où BeanB est câblé dans BeanA mais il n'est pas défini:

@Component public class BeanA { @Autowired private BeanB dependency; //... }

Si nous essayons d'exécuter cette application simple, cela tente de charger BeanA :

@SpringBootApplication public class NoSuchBeanDefinitionDemoApp { public static void main(String[] args) { SpringApplication.run(NoSuchBeanDefinitionDemoApp.class, args); } }

L'application ne démarrera pas avec le message d'erreur:

*************************** APPLICATION FAILED TO START *************************** Description: Field dependency in com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA required a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' that could not be found. Action: Consider defining a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' in your configuration.

Ici, com.baeldung.springbootmvc.nosuchbeandefinitionexception est le package pour BeanA , BeanB et NoSuchBeanDefinitionDemoApp .

L'extrait de cet exemple se trouve dans ce projet Github.

4. Cause: Aucun bean éligible de type […] n'est défini

Une autre cause de l'exception est l'existence de deux définitions de bean dans le contexte, au lieu d'une. Par exemple, si une interface - IBeanB est implémentée par deux beans - BeanB1 et BeanB2 :

@Component public class BeanB1 implements IBeanB { // } @Component public class BeanB2 implements IBeanB { // }

Maintenant, si BeanA active cette interface, Spring ne saura pas laquelle des deux implémentations injecter:

@Component public class BeanA { @Autowired private IBeanB dependency; ... }

Et encore une fois, cela entraînera une NoSuchBeanDefinitionException levée par le BeanFactory :

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: expected single matching bean but found 2: beanB1,beanB2

De même, Spring indique clairement la raison de l'échec du câblage: «seul bean correspondant attendu mais trouvé 2» .

Notez, cependant, que dans ce cas, l'exception exacte levée n'est pas NoSuchBeanDefinitionException mais une sous-classe - la NoUniqueBeanDefinitionException . Cette nouvelle exception a été introduite au printemps 3.2.1, précisément pour cette raison - pour différencier la cause où aucune définition de bean n'a été trouvée et celle-ci - où plusieurs définitions se trouvent dans le contexte.

Avant ce changement, l'exception ci-dessus était:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: expected single matching bean but found 2: beanB1,beanB2

Une solution à ce problème consiste à utiliser l' annotation @Qualifier pour spécifier exactement le nom du bean que nous voulons câbler:

@Component public class BeanA { @Autowired @Qualifier("beanB2") private IBeanB dependency; ... }

Maintenant, Spring a suffisamment d'informations pour décider quel bean injecter - BeanB1 ou BeanB2 (le nom par défaut de BeanB2 est beanB2 ).

5. Cause: aucun bean nommé […] n'est défini

Une NoSuchBeanDefinitionException peut également être levée lorsqu'un bean qui n'est pas défini est demandé par son nom dans le contexte Spring:

@Component public class BeanA implements InitializingBean { @Autowired private ApplicationContext context; @Override public void afterPropertiesSet() { context.getBean("someBeanName"); } }

Dans ce cas, il n'y a pas de définition de bean pour "someBeanName" - conduisant à l'exception suivante:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'someBeanName' is defined

Là encore, Spring indique clairement et de manière concise la raison de l'échec: « Aucun bean nommé X n'est défini ».

6. Cause: Beans proxy

When a bean in the context is proxied using the JDK Dynamic Proxy mechanism, then the proxy will not extend the target bean (it will, however, implement the same interfaces).

Because of this, if the bean is injected by an interface, it will be correctly wired in. If however the bean is injected by the actual class, then Spring will not find a bean definition that matches the class – since the proxy does not actually extend the class.

A very common reason the bean may be proxied is the Spring transactional support – namely beans that are annotated with @Transactional.

Par exemple, si ServiceA injecte ServiceB et que les deux services sont transactionnels, l' injection par la définition de classe ne fonctionnera pas:

@Service @Transactional public class ServiceA implements IServiceA{ @Autowired private ServiceB serviceB; ... } @Service @Transactional public class ServiceB implements IServiceB{ ... }

Les deux mêmes services, cette fois injectés correctement par l'interface , seront OK:

@Service @Transactional public class ServiceA implements IServiceA{ @Autowired private IServiceB serviceB; ... } @Service @Transactional public class ServiceB implements IServiceB{ ... }

7. Conclusion

Ce didacticiel a présenté des exemples des causes possibles de l' exception NoSuchBeanDefinitionException courante, en mettant l' accent sur la manière de résoudre ces exceptions dans la pratique.

L'implémentation de tous ces exemples d'exceptions peut être trouvée dans le projet GitHub - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.

Enfin, la liste complète des exceptions et des solutions de Spring pourrait être une bonne ressource à mettre en signet.