1. Pengenalan
Peningkatan Spring Boot 2.1 mengejutkan beberapa orang dengan kejadian BeanDefinitionOverrideException yang tidak dijangka . Ini boleh mengelirukan sebilangan pemaju dan membuat mereka tertanya-tanya tentang apa yang berlaku dengan tingkah laku pengganti kacang pada musim bunga.
Dalam tutorial ini, kami akan membongkar masalah ini dan melihat cara terbaik untuk mengatasinya.
2. Pergantungan Maven
Sebagai contoh projek Maven, kita perlu menambahkan pergantungan Spring Boot Starter:
org.springframework.boot spring-boot-starter 2.3.3.RELEASE
3. Kacang Kacang
Kacang pegas dikenali dengan namanya dalam ApplicationContext .
Oleh itu, penggantian kacang adalah tingkah laku lalai yang berlaku ketika kita menentukan kacang dalam ApplicationContext yang mempunyai nama yang sama dengan kacang lain . Ia berfungsi dengan hanya menggantikan bekas kacang sekiranya terdapat konflik nama.
Bermula pada musim bunga 5.1, BeanDefinitionOverrideException diperkenalkan untuk membolehkan pembangun membuang pengecualian secara automatik untuk mengelakkan penggantian kacang yang tidak dijangka . Secara lalai, tingkah laku asal masih ada yang membolehkan penggantian kacang.
4. Perubahan Konfigurasi untuk Spring Boot 2.1
Spring Boot 2.1 kacang kurang upaya ditimpa secara lalai sebagai pendekatan pertahanan. Tujuan utamanya adalah untuk memperhatikan pendua nama kacang terlebih dahulu untuk mengelakkan kacang yang berlebihan .
Oleh itu, jika aplikasi Spring Boot kami bergantung pada penggantian kacang, kemungkinan besar akan menemui BeanDefinitionOverrideException setelah kami meningkatkan versi Spring Boot ke 2.1 dan yang lebih baru.
Pada bahagian seterusnya, kita akan melihat contoh di mana BeanDefinitionOverrideException akan berlaku, dan kemudian kita akan membincangkan beberapa penyelesaian.
5. Mengenal Kacang dalam Konflik
Mari buat dua konfigurasi Spring yang berbeza, masing-masing dengan kaedah testBean () , untuk menghasilkan BeanDefinitionOverrideException:
@Configuration public class TestConfiguration1 { class TestBean1 { private String name; // standard getters and setters } @Bean public TestBean1 testBean(){ return new TestBean1(); } }
@Configuration public class TestConfiguration2 { class TestBean2 { private String name; // standard getters and setters } @Bean public TestBean2 testBean(){ return new TestBean2(); } }
Seterusnya, kami akan membuat kelas ujian Spring Boot kami:
@RunWith(SpringRunner.class) @SpringBootTest(classes = {TestConfiguration1.class, TestConfiguration2.class}) public class SpringBootBeanDefinitionOverrideExceptionIntegrationTest { @Test public void whenBeanOverridingAllowed_thenTestBean2OverridesTestBean1() { Object testBean = applicationContext.getBean("testBean"); assertThat(testBean.getClass()).isEqualTo(TestConfiguration2.TestBean2.class); } }
Menjalankan ujian menghasilkan BeanDefinitionOverrideException . Walau bagaimanapun, pengecualian ini memberi kami beberapa maklumat berguna:
Invalid bean definition with name 'testBean' defined in ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration2 ... Cannot register bean definition [ ... defined in ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration2] for bean 'testBean' ... There is already [ ... defined in ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration1] bound.
Perhatikan bahawa pengecualian itu mendedahkan dua maklumat penting.
Yang pertama adalah nama kacang yang bertentangan, testBean :
Invalid bean definition with name 'testBean' ...
Dan yang kedua menunjukkan jalan penuh konfigurasi yang terjejas:
... com.baeldung.beandefinitionoverrideexception.TestConfiguration2 ... ... com.baeldung.beandefinitionoverrideexception.TestConfiguration1 ...
Hasilnya, kita dapat melihat bahawa dua biji yang berbeza dikenal pasti sebagai testBean yang menyebabkan konflik. Selain itu, kacang terkandung di dalam kelas konfigurasi TestConfiguration1 dan TestConfiguration2 .
6. Penyelesaian yang Mungkin
Bergantung pada konfigurasi kami, Spring Beans mempunyai nama lalai kecuali kami menetapkannya secara jelas.
Oleh itu, penyelesaian pertama yang mungkin adalah menukar nama kacang.
Terdapat beberapa cara biasa untuk menetapkan nama kacang pada musim bunga.
6.1. Menukar Nama Kaedah
Secara lalai, Spring mengambil nama kaedah anotasi sebagai nama kacang .
Oleh itu, jika kita mempunyai kacang yang ditentukan dalam kelas konfigurasi, seperti contoh kita, maka dengan menukar nama kaedah akan mengelakkan BeanDefinitionOverrideException :
@Bean public TestBean1 testBean1() { return new TestBean1(); }
@Bean public TestBean2 testBean2() { return new TestBean2(); }
6.2. @Bot Anotasi
Anotasi Spring @Bean adalah cara yang sangat biasa untuk menentukan kacang.
Oleh itu, satu lagi pilihan adalah untuk menetapkan nama harta @Bean anotasi:
@Bean("testBean1") public TestBean1 testBean() { return new TestBean1(); }
@Bean("testBean2") public TestBean1 testBean() { return new TestBean2(); }
6.3. Anotasi Stereotaip
Kaedah lain untuk menentukan kacang adalah dengan anotasi stereotaip. Dengan ciri @ComponentScan Spring yang diaktifkan, kami dapat menentukan nama kacang kami di peringkat kelas menggunakan anotasi @Component :
@Component("testBean1") class TestBean1 { private String name; // standard getters and setters }
@Component("testBean2") class TestBean2 { private String name; // standard getters and setters }
6.4. Kacang Berasal Dari Perpustakaan Pihak Ketiga
Dalam beberapa kes, mungkin terdapat konflik nama yang disebabkan oleh kacang yang berasal dari perpustakaan pihak ketiga yang disokong oleh musim bunga .
Apabila ini berlaku, kita harus berusaha untuk mengenal pasti kacang yang bertentangan dalam aplikasi kita, untuk menentukan apakah ada penyelesaian di atas yang dapat digunakan.
Namun, jika kita tidak dapat mengubah definisi kacang, maka mengkonfigurasi Spring Boot untuk membenarkan penggantian kacang boleh menjadi jalan keluar.
Untuk mengaktifkan penggantian kacang, mari tetapkan sifat spring.main.allow-bean-definisi-overriding menjadi benar dalam fail application.properties kami :
spring.main.allow-bean-definition-overriding=true
Dengan melakukan ini, kami memberitahu Spring Boot untuk membiarkan kacang berlebihan tanpa perubahan pada definisi kacang.
Sebagai notis terakhir, kita harus sedar bahawa sukar untuk menebak kacang mana yang akan diutamakan kerana urutan pembuatan kacang ditentukan oleh hubungan ketergantungan yang kebanyakannya dipengaruhi pada waktu proses . Oleh itu, membiarkan penggantian kacang boleh menghasilkan tingkah laku yang tidak dijangka kecuali kita mengetahui hierarki kebergantungan kacang kita dengan cukup baik.
7. Kesimpulannya
Dalam tutorial ini, kami menerangkan apa maksud BeanDefinitionOverrideException pada musim bunga, mengapa ia tiba-tiba muncul, dan bagaimana mengatasinya setelah peningkatan Spring Boot 2.1.
Seperti biasa, kod sumber lengkap artikel ini boleh didapati di GitHub.