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.