Vår NoSuchBeanDefinitionException

1. Oversikt

I denne artikkelen diskuterer vi Vår org.springframework.beans.factory.NoSuchBeanDefinitionException - dette er et vanlig unntak kastet av BeanFactory når du prøver å løse en bønne som rett og slett ikke er definert i vårkonteksten.

Vi illustrerer mulige årsaker til dette problemet og tilgjengelige løsninger.

Og selvfølgelig skjer unntak når du minst forventer dem; ta en titt på den komplette listen over unntak og løsninger på våren.

2. Årsak: Ingen kvalifiserende bønner av typen […] funnet for avhengighet

Den vanligste årsaken til dette unntaket er bare å prøve å injisere en bønne som ikke er definert. For eksempel - BeanB kobler til en samarbeidspartner - BeanA:

@Komponent offentlig klasse BeanA {@Autowired privat BeanB avhengighet; // ...}

Nå, hvis avhengigheten - BeanB - ikke er definert i vårkonteksten, vil bootstrap-prosessen mislykkes med ikke noe slikt bønnedefinisjons unntak:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Ingen kvalifiserende bønner av typen [com.baeldung.packageB.BeanB] funnet for avhengighet: forventet minst 1 bønne som kvalifiserer som autowire-kandidat for denne avhengigheten. Avhengighetsanmerkninger: {@ org.springframework.beans.factory.annotation.Autowired (required = true)}

Årsaken er tydelig indikert av våren: “forventet minst 1 bønne som kvalifiserer som autowire-kandidat for denne avhengigheten

En grunn BeanB eksisterer kanskje ikke i konteksten - hvis bønner plukkes opp automatisk av klassesti skanning, og hvis BeanB er korrekt kommentert som en bønne (@Komponent, @Oppbevaringssted, @Service, @Kontrollør, etc) - er at den kan defineres i en pakke som ikke er skannet av våren:

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

Mens classpath-skanningen kan konfigureres som følger:

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

Hvis bønner ikke skannes automatisk av i stedet definert manuelt, deretter BeanB er ganske enkelt ikke definert i gjeldende vårkontekst.

3. Årsak: Felt […] i […] Krevde en bønne av typen […] som ikke ble funnet

I en Spring Boot-applikasjon for scenariet ovenfor får vi en annen melding.

La oss ta det samme eksemplet hvor BeanB er kablet inn BeanA men det er ikke definert:

@Komponent offentlig klasse BeanA {@Autowired privat BeanB avhengighet; // ...}

Hvis vi prøver å kjøre dette enkle programmet, prøver det å laste det inn BeanA:

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

Søknaden starter ikke med feilmeldingen:

*************************** SØKNAD KAN IKKE STARTE ****************** ******** Beskrivelse: Feltavhengighet i com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA krevde en bønne av typen 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' som ikke ble funnet. Handling: Vurder å definere en bønne av typen 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' i konfigurasjonen.

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

Utdraget for dette eksemplet finner du i dette Github-prosjektet.

4. Årsak: Ingen kvalifiserende bønner av typen […] er definert

En annen årsak til unntaket er eksistensen av to bønnedefinisjoner i sammenhengen, i stedet for en. For eksempel hvis et grensesnitt - IBeanB er implementert av to bønner - BeanB1 og BeanB2:

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

Nå, hvis BeanA autowires dette grensesnittet, vil Spring ikke vite hvilken av de to implementeringene som skal injiseres:

@Komponent offentlig klasse BeanA {@Autowired privat IBeanB avhengighet; ...}

Og igjen vil dette resultere i en NoSuchBeanDefinitionException blir kastet av BeanFactory:

Forårsaket av: org.springframework.beans.factory.NoUniqueBeanDefinitionException: Ingen kvalifiserende bønner av typen [com.baeldung.packageB.IBeanB] er definert: forventet enkelt matchende bønne men funnet 2: beanB1, beanB2

På samme måte indikerer Spring tydelig årsaken til ledningsfeilen: “Forventet single matching bean but found 2”.

Legg merke til at det eksakte unntaket som kastes i dette tilfellet ikke er NoSuchBeanDefinitionException men en underklasse - de NoUniqueBeanDefinitionException. Dette nye unntaket ble introdusert våren 3.2.1, nettopp av denne grunn - for å skille mellom årsaken der ingen bønnedefinisjon ble funnet og denne - der flere definisjoner finnes i sammenhengen.

Før denne endringen var unntaket ovenfor:

Forårsaket av: org.springframework.beans.factory.NoSuchBeanDefinitionException: Ingen kvalifiserende bønner av typen [com.baeldung.packageB.IBeanB] er definert: forventet enkelt matchende bønne men funnet 2: beanB1, beanB2

En løsningen på dette problemet er å bruke @Kvalifiserende kommentar for å spesifisere nøyaktig navnet på bønnen vi vil koble til:

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

Nå har Spring nok informasjon til å ta en beslutning om hvilken bønne som skal injiseres - BeanB1 eller BeanB2 (standardnavnet på BeanB2 er bønneB2).

5. Årsak: Ingen bønner navngitt […] er definert

EN NoSuchBeanDefinitionException kan også kastes når en bønne som ikke er definert er etterspurt etter navn fra vårkonteksten:

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

I dette tilfellet er det ingen definisjon av bønner for “someBeanName” - noe som fører til følgende unntak:

Forårsaket av: org.springframework.beans.factory.NoSuchBeanDefinitionException: Ingen bønne med navnet 'someBeanName' er definert

Igjen indikerer Spring tydelig og kortfattet årsaken til feilen: “Ingen bønner med navnet X er definert“.

6. Årsak: Proxied Beans

Når en bønne i konteksten er proxied ved hjelp av JDK Dynamic Proxy-mekanismen, da proxyen utvider ikke målbønnen (det vil imidlertid implementere de samme grensesnittene).

På grunn av dette, hvis bønnen injiseres av et grensesnitt, vil den være riktig koblet til. Hvis bønnen imidlertid injiseres av den faktiske klassen, vil ikke Spring finne en bønnedefinisjon som samsvarer med klassen - siden proxyen faktisk ikke utvide klassen.

En veldig vanlig årsak til at bønnen kan være proxy er Vår transaksjonell støtte - nemlig bønner som er merket med @Transaksjonell.

For eksempel hvis Tjeneste A. injiserer ServiceB, og begge tjenestene er transaksjonelle, injeksjon etter klassedefinisjonen vil ikke fungere:

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

De samme to tjenestene, denne gangen riktig injisere ved grensesnittet, vil bli ok:

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

7. Konklusjon

Denne opplæringen diskuterte eksempler på mulige årsaker til det vanlige NoSuchBeanDefinitionException - med fokus på hvordan man skal adressere disse unntakene i praksis.

Implementeringen av alle disse unntakseksemplene finnes i GitHub-prosjektet - dette er et Eclipse-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.

Endelig, hele listen over unntak og løsninger om våren kan det være en god ressurs å legge til bokmerker.