The BeanDefinitionOverrideException in Spring Boot

1. Introduksjon

Spring Boot 2.1-oppgraderingen overrasket flere mennesker med uventede forekomster av BeanDefinitionOverrideException. Det kan forvirre noen utviklere og få dem til å lure på hva som skjedde med bønns overordnede oppførsel våren.

I denne opplæringen vil vi løse problemet og se hvordan vi best kan løse det.

2. Maven-avhengigheter

For vårt eksempel Maven-prosjekt, må vi legge til Spring Boot Starter avhengighet:

 org.springframework.boot spring-boot-starter 2.3.3.RELEASE 

3. Bønneoverstyring

Vårbønner identifiseres av navnene deres innen ApplicationContext.

Og dermed, bønneoverstyring er en standard atferd som skjer når vi definerer en bønne i en ApplicationContext som har samme navn som en annen bønne. Det fungerer ved å bare erstatte den tidligere bønnen i tilfelle en navnekonflikt.

Fra og med våren 5.1 BeanDefinitionOverrideException ble introdusert for å tillate utviklere å automatisk kaste unntaket for å forhindre uventet overstyring av bønner. Som standard er den opprinnelige oppførselen fremdeles tilgjengelig som gjør det mulig å overstyre bønner.

4. Konfigurasjonsendring for Spring Boot 2.1

Spring Boot 2.1 deaktivert bønneoverstyring som standard som en defensiv tilnærming. Hovedformålet er å legg merke til de dupliserte bønnenavnene på forhånd for å forhindre overstyrende bønner ved et uhell.

Derfor, hvis vår Spring Boot-applikasjon er avhengig av overstyring av bønner, er det veldig sannsynlig å støte på BeanDefinitionOverrideException etter at vi oppgraderer Spring Boot-versjonen til 2.1 og senere.

I de neste avsnittene vil vi se på et eksempel der BeanDefinitionOverrideException ville oppstå, og så vil vi diskutere noen løsninger.

5. Identifisere bønnene i konflikt

La oss lage to forskjellige vårkonfigurasjoner, hver med en testBean () metode, for å produsere BeanDefinitionOverrideException:

@Configuration offentlig klasse TestConfiguration1 {klasse TestBean1 {privat strengnavn; // standard getters and setters} @Bean public TestBean1 testBean () {return new TestBean1 (); }} 
@Configuration offentlig klasse TestConfiguration2 {klasse TestBean2 {privat strengnavn; // standard getters and setters} @Bean public TestBean2 testBean () {returner ny TestBean2 (); }} 

Deretter lager vi vår Spring Boot testklasse:

@RunWith (SpringRunner.class) @SpringBootTest (klasser = {TestConfiguration1.class, TestConfiguration2.class}) public class SpringBootBeanDefinitionOverrideExceptionIntegrationTest {@Test public void whenBeanOverridingAllowed_thenTestBean2OverreanTestTestBean2OverridesTestTestBean2OverridesTestTestBean2OverridesTest assertThat (testBean.getClass ()). isEqualTo (TestConfiguration2.TestBean2.class); }} 

Å kjøre testen gir en BeanDefinitionOverrideException. Unntaket gir oss imidlertid nyttig informasjon:

Ugyldig bønnedefinisjon med navnet 'testBean' definert i ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration2 ... Kan ikke registrere bean definition [... definert i ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration2] for bean 'testBean' ... Det er allerede [... definert i ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration1] bundet. 

Legg merke til at unntaket avslører to viktige opplysninger.

Den første er det motstridende bønnenavnet, testBean:

Ugyldig bønnedefinisjon med navnet 'testBean' ... 

Og det andre viser oss hele banen til de berørte konfigurasjonene:

... com.baeldung.beandefinitionoverrideexception.TestConfiguration2 ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration1 ... 

Som et resultat kan vi se at to forskjellige bønner er identifisert som testBean forårsaker en konflikt. I tillegg er bønnene inne i konfigurasjonsklassene Testkonfigurasjon 1 og Testkonfigurasjon2.

6. Mulige løsninger

Avhengig av konfigurasjonen vår har Spring Beans standardnavn med mindre vi angir dem eksplisitt.

Derfor er den første mulige løsningen å gi nytt navn til bønnene våre.

Det er noen vanlige måter å sette bønnenavn på våren.

6.1. Endring av metodenavn

Som standard, Våren tar navnet på de merkede metodene som bønnenavn.

Derfor, hvis vi har definert bønner i en konfigurasjonsklasse, som eksempelet vårt, vil det bare å endre metodenavnene forhindre BeanDefinitionOverrideException:

@Bean offentlig TestBean1 testBean1 () {returner ny TestBean1 (); } 
@Bean offentlig TestBean2 testBean2 () {returner ny TestBean2 (); } 

6.2. @Bønne Kommentar

Vårens @Bønne kommentar er en veldig vanlig måte å definere en bønne på.

Dermed er et annet alternativ å stille inn Navn tilhører @Bønne kommentar:

@Bean ("testBean1") offentlig TestBean1 testBean () {returner ny TestBean1 (); } 
@Bean ("testBean2") offentlig TestBean1 testBean () {returner ny TestBean2 (); } 

6.3. Stereotype kommentarer

En annen måte å definere en bønne på er med stereotype merknader. Med vårens @ComponentScan funksjon aktivert, kan vi definere bønnenavnene våre på klassenivå ved hjelp av @Komponent kommentar:

@Component ("testBean1") klasse TestBean1 {privat strengnavn; // standard getters og setters} 
@Component ("testBean2") klasse TestBean2 {privat strengnavn; // standard getters og setters} 

6.4. Bønner som kommer fra tredjepartsbiblioteker

I noen tilfeller, det er mulig å støte på en navnekonflikt forårsaket av bønner som kommer fra tredjeparts vårstøttede biblioteker.

Når dette skjer, bør vi prøve å identifisere hvilken motstridende bønne som tilhører applikasjonen vår, for å avgjøre om noen av løsningene ovenfor kan brukes.

Imidlertid, hvis vi ikke klarer å endre noen av bønnedefinisjonene, kan det være en løsning å konfigurere Spring Boot for å tillate bønneoverstyring.

For å aktivere bønneoverstyring, la oss stille inn spring.main.allow-bean-definition-overriding eiendom til ekte i vår application.properties fil:

spring.main.allow-bean-definition-overriding = true 

Ved å gjøre dette ber vi Spring Boot om å tillate bønneoverstyring uten noen endring i bønnedefinisjoner.

Som et siste varsel, bør vi være klar over det det er vanskelig å gjette hvilken bønne som vil ha prioritet fordi ordningen for bønneopprettelsen bestemmes av avhengighetsforhold som hovedsakelig påvirkes i kjøretid. Derfor kan tillatelse av bønneoverstyring gi uventet oppførsel med mindre vi kjenner avhengighetshierarkiet til bønnene våre godt nok.

7. Konklusjon

I denne opplæringen forklarte vi hva BeanDefinitionOverrideException betyr på våren, hvorfor det plutselig dukker opp, og hvordan man adresserer det etter Spring Boot 2.1-oppgraderingen.

Som alltid kan du finne den fullstendige kildekoden til denne artikkelen på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found