Forår NoSuchBeanDefinitionException

1. Oversigt

I denne artikel diskuterer vi Forår org.springframework.beans.factory.NoSuchBeanDefinitionException - dette er en almindelig undtagelse kastet af BeanFactory når du prøver at løse en bønne, der simpelthen ikke er defineret i foråret sammenhæng.

Vi illustrerer de mulige årsager til dette problem og de tilgængelige løsninger.

Og selvfølgelig sker der undtagelser, når du mindst venter dem; se på den fulde liste over undtagelser og løsninger i foråret.

2. Årsag: Ingen kvalificerende bønner af typen [...] fundet for afhængighed

Den mest almindelige årsag til denne undtagelse er simpelthen at prøve at injicere en bønne, der ikke er defineret. For eksempel - BeanB er ledning i en samarbejdspartner - BeanA:

@Komponent offentlig klasse BeanA {@Autowired privat BeanB-afhængighed; // ...}

Nu, hvis afhængigheden - BeanB - er ikke defineret i Spring Context, bootstrap-processen mislykkes med ingen sådan bøndefinition undtagelse:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Ingen kvalificerende bønner af typen [com.baeldung.packageB.BeanB] fundet for afhængighed: forventes mindst 1 bønne, der kvalificerer som autowire-kandidat for denne afhængighed. Afhængighedsannotationer: {@ org.springframework.beans.factory.annotation.Autowired (krævet = true)}

Årsagen er tydeligt angivet af foråret: “forventede mindst 1 bønne, der kvalificerer sig som autowire-kandidat til denne afhængighed

En grund BeanB findes muligvis ikke i sammenhængen - hvis bønner plukkes automatisk op af klassesti-scanning, og hvis BeanB er korrekt kommenteret som en bønne (@Komponent, @Repository, @Service, @Kontrolosv. - er, at det kan defineres i en pakke, der ikke er scannet af Spring:

pakke com.baeldung.packageB; @Komponent offentlig klasse BeanB {...}

Mens classpath-scanningen kan konfigureres som følger:

@Configuration @ComponentScan ("com.baeldung.packageA") offentlig klasse ContextWithJavaConfig {...}

Hvis bønner ikke automatisk scannes af i stedet defineres manuelt, derefter BeanB er simpelthen ikke defineret i den aktuelle Spring Context.

3. Årsag: Felt […] i […] krævede en bønne af typen […] der ikke kunne findes

I en Spring Boot-applikation til ovenstående scenarie får vi en anden besked.

Lad os tage det samme eksempel hvor BeanB er tilsluttet BeanA men det er ikke defineret:

@Komponent offentlig klasse BeanA {@Autowired privat BeanB-afhængighed; // ...}

Hvis vi forsøger at køre denne enkle applikation, forsøger den at indlæse BeanA:

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

Applikationen starter ikke med fejlmeddelelsen:

*************************** ANSØGNING MISLYKKEDE START ****************** ******** Beskrivelse: Markafhængighed i com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA krævede en bønne af typen 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB', der ikke kunne findes. Handling: Overvej at definere en bønne af typen 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' i din konfiguration.

Her, com.baeldung.springbootmvc.nosuchbeandefinitionexception er pakken til BeanA, BeanB og NoSuchBeanDefinitionDemoApp.

Kodestykket til dette eksempel kan findes i dette Github-projekt.

4. Årsag: Ingen kvalificerende bønner af typen […] er defineret

En anden årsag til undtagelsen er eksistensen af ​​to bønnedefinitioner i sammenhængen i stedet for en. For eksempel, hvis en grænseflade - IBeanB er implementeret af to bønner - BønneB1 og BeanB2:

@Komponent offentlig klasse BeanB1 implementerer IBeanB {//} @Komponent offentlig klasse BeanB2 implementerer IBeanB {//}

Nu, hvis BeanA autowires denne grænseflade, Spring ved ikke, hvilken af ​​de to implementeringer der skal injiceres:

@Komponent offentlig klasse BeanA {@Autowired privat IBeanB-afhængighed; ...}

Og igen vil dette resultere i en NoSuchBeanDefinitionException bliver kastet af BeanFactory:

Forårsaget af: org.springframework.beans.factory.NoUniqueBeanDefinitionException: Ingen kvalificerende bønne af typen [com.baeldung.packageB.IBeanB] er defineret: forventet enkelt matchende bønne men fundet 2: beanB1, beanB2

På samme måde angiver Spring tydeligt årsagen til ledningsfejl: “Forventet enkelt matchende bønne men fundet 2”.

Bemærk dog, at i dette tilfælde er den nøjagtige undtagelse, der kastes, ikke NoSuchBeanDefinitionException men en underklasse - det NoUniqueBeanDefinitionException. Denne nye undtagelse blev introduceret i foråret 3.2.1 af netop denne grund - for at skelne mellem årsagen, hvor der ikke blev fundet en bønnedefinition, og denne - hvor flere definitioner findes i sammenhængen.

Før denne ændring var undtagelsen ovenfor:

Forårsaget af: org.springframework.beans.factory.NoSuchBeanDefinitionException: Ingen kvalificerende bønne af typen [com.baeldung.packageB.IBeanB] er defineret: forventet enkelt matchende bønne men fundet 2: beanB1, beanB2

En løsningen på dette problem er at bruge @Kvalifikator kommentar for at specificere nøjagtigt navnet på den bønne, vi vil tilslutte:

@Komponent offentlig klasse BeanA {@Autowired @Qualifier ("beanB2") privat IBeanB-afhængighed; ...}

Nu har Spring nok oplysninger til at træffe beslutningen om, hvilken bønne der skal injiceres - BønneB1 eller BeanB2 (standardnavnet på BeanB2 er bønneB2).

5. Årsag: Ingen bønner navngivet […] er defineret

EN NoSuchBeanDefinitionException kan også kastes, når en bønne, der ikke er defineret, er anmodet om ved navn fra forårssammenhæng:

@Component public class BeanA implementerer InitializingBean {@Autowired private ApplicationContext context; @ Overstyr offentlig ugyldighed efterPropertiesSet () {context.getBean ("someBeanName"); }}

I dette tilfælde er der ingen bøndefinition for "someBeanName" - hvilket fører til følgende undtagelse:

Forårsaget af: org.springframework.beans.factory.NoSuchBeanDefinitionException: Ingen bønne med navnet 'someBeanName' er defineret

Igen angiver Spring tydeligt og kortfattet årsagen til fiaskoen: “Ingen bønner med navnet X er defineret“.

6. Årsag: Proxied Beans

Når en bønne i konteksten proxies ved hjælp af JDK Dynamic Proxy-mekanismen, så proxyen udvider ikke målbønnen (det vil dog implementere de samme grænseflader).

På grund af dette, hvis bønnen injiceres af en grænseflade, vil den blive tilsluttet korrekt. Hvis bønnen dog injiceres af den aktuelle klasse, finder Spring ikke en bønnedefinition, der matcher klassen - da proxyen faktisk ikke udvid klassen.

En meget almindelig årsag til, at bønnen kan proxies, er Forårstransaktionel support - nemlig bønner, der er kommenteret med @Transaktionel.

For eksempel hvis ServiceA injicerer ServiceB, og begge tjenester er transaktionsmæssige, indsprøjtning efter klassedefinitionen vil ikke virke:

@Service @Transaktionel offentlig klasse ServiceA implementerer IServiceA {@Autowired privat ServiceB serviceB; ...} @Service @Transactional public class ServiceB implementerer IServiceB {...}

De samme to tjenester, denne gang korrekt indsprøjtning ved grænsefladen, vil være OK:

@Service @Transactional public class ServiceA implementerer IServiceA {@Autowired privat IServiceB serviceB; ...} @Service @Transactional public class ServiceB implementerer IServiceB {...}

7. Konklusion

Denne tutorial diskuterede eksempler på mulige årsager til det fælles NoSuchBeanDefinitionException - med fokus på, hvordan man undgår disse undtagelser i praksis.

Implementeringen af ​​alle disse undtagelseseksempler findes i GitHub-projektet - dette er et Eclipse-baseret projekt, så det skal være let at importere og køre som det er.

Langt om længe, den fulde liste over undtagelser og løsninger om foråret kan det være en god ressource at bogmærke.