1. Gambaran keseluruhan
Dalam artikel ini, kita membincangkan org.springframework.beans.factory.NoSuchBeanDefinitionException Spring - ini adalah pengecualian biasa yang dilemparkan oleh BeanFactory ketika cuba menyelesaikan kacang yang tidak ditentukan dalam Konteks Musim Semi.
Kami akan menerangkan kemungkinan penyebab masalah ini dan penyelesaian yang ada.
Dan tentu saja, pengecualian berlaku apabila anda paling tidak mengharapkannya; lihat senarai penuh pengecualian dan penyelesaian pada musim bunga.
2. Sebab: Tidak Ada Kacang Kelayakan Jenis […] Ditemukan untuk Ketergantungan
Penyebab pengecualian yang paling biasa adalah hanya mencuba memasukkan kacang yang tidak ditentukan. Contohnya - BeanB adalah pendawaian dalam kolaborator - BeanA:
@Component public class BeanA { @Autowired private BeanB dependency; //... }
Sekarang, jika kebergantungan - BeanB - tidak ditentukan dalam Spring Context, proses bootstrap akan gagal dengan pengecualian definisi kacang seperti itu :
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.BeanB] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Sebabnya ditunjukkan dengan jelas oleh Spring: " diharapkan sekurang-kurangnya 1 biji yang memenuhi syarat sebagai calon autowire untuk kebergantungan ini "
Salah satu sebab BeanB mungkin tidak wujud dalam konteks - jika kacang diambil secara automatik dengan pengimbasan classpath , dan jika BeanB diberi anotasi dengan betul sebagai kacang ( @Component , @Repository , @Service , @Controller , dll) - adalah mungkin ditentukan dalam pakej yang tidak diimbas oleh Spring :
package com.baeldung.packageB; @Component public class BeanB { ...}
Walaupun pengimbasan classpath boleh dikonfigurasi seperti berikut:
@Configuration @ComponentScan("com.baeldung.packageA") public class ContextWithJavaConfig { ... }
Sekiranya kacang tidak diimbas secara automatik sebaliknya ditakrifkan secara manual , maka BeanB tidak ditentukan dalam Konteks Musim Semi semasa.
3. Sebab: Medan […] di […] Memerlukan Biji Jenis […] Yang Tidak Dapat Dijumpai
Dalam aplikasi Spring Boot untuk senario di atas, kami mendapat mesej yang berbeza.
Mari kita ambil contoh yang sama di mana BeanB berwayar di BeanA tetapi tidak ditentukan:
@Component public class BeanA { @Autowired private BeanB dependency; //... }
Sekiranya kita cuba menjalankan aplikasi mudah ini, yang cuba memuatkan BeanA :
@SpringBootApplication public class NoSuchBeanDefinitionDemoApp { public static void main(String[] args) { SpringApplication.run(NoSuchBeanDefinitionDemoApp.class, args); } }
Aplikasi akan gagal dimulakan dengan mesej ralat:
*************************** APPLICATION FAILED TO START *************************** Description: Field dependency in com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanA required a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' that could not be found. Action: Consider defining a bean of type 'com.baeldung.springbootmvc.nosuchbeandefinitionexception.BeanB' in your configuration.
Di sini, com.baeldung.springbootmvc.nosuchbeandefinitionexception adalah pakej untuk BeanA , BeanB dan NoSuchBeanDefinitionDemoApp .
Coretan untuk contoh ini boleh didapati dalam projek Github ini.
4. Sebab: Tidak Ada Kekacang Jenis […] Yang Ditentukan
Sebab lain untuk pengecualian adalah adanya dua definisi kacang dalam konteks, dan bukannya satu. Sebagai contoh, jika antara muka - IBeanB dilaksanakan oleh dua kacang - BeanB1 dan BeanB2 :
@Component public class BeanB1 implements IBeanB { // } @Component public class BeanB2 implements IBeanB { // }
Sekarang, jika BeanA mengautomasikan antara muka ini, Spring tidak akan mengetahui mana satu daripada dua pelaksanaan yang akan disuntik:
@Component public class BeanA { @Autowired private IBeanB dependency; ... }
Dan sekali lagi, ini akan menghasilkan pengecualian NoSuchBeanDefinitionException oleh BeanFactory :
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: expected single matching bean but found 2: beanB1,beanB2
Begitu juga, Spring dengan jelas menunjukkan sebab kegagalan pendawaian: "kacang tunggal yang diharapkan tetapi dijumpai 2" .
Notis, bagaimanapun, bahawa dalam kes ini, kecuali yang tepat yang dilemparkan tidak NoSuchBeanDefinitionException tetapi subkelas - yang NoUniqueBeanDefinitionException . Pengecualian baru ini telah diperkenalkan pada Musim Semi 3.2.1, untuk alasan ini - untuk membezakan antara sebab di mana tidak ada definisi kacang dan yang ini - di mana terdapat beberapa definisi dalam konteksnya.
Sebelum perubahan ini, pengecualian di atas adalah:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.baeldung.packageB.IBeanB] is defined: expected single matching bean but found 2: beanB1,beanB2
Salah satu penyelesaian untuk masalah ini adalah dengan menggunakan anotasi @Qualifier untuk menentukan dengan tepat nama kacang yang ingin kami kumpulkan :
@Component public class BeanA { @Autowired @Qualifier("beanB2") private IBeanB dependency; ... }
Sekarang Spring mempunyai cukup maklumat untuk membuat keputusan kacang mana yang hendak disuntik - BeanB1 atau BeanB2 (nama lalai BeanB2 adalah beanB2 ).
5. Sebab: Tidak Ada Kacang Dinamakan […] Ditentukan
A NoSuchBeanDefinitionException juga boleh dibuang apabila kacang yang tidak tertakrif dengan disebutkan namanya dari konteks Spring:
@Component public class BeanA implements InitializingBean { @Autowired private ApplicationContext context; @Override public void afterPropertiesSet() { context.getBean("someBeanName"); } }
Dalam kes ini, tidak ada definisi kacang untuk "someBeanName" - yang membawa kepada pengecualian berikut:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'someBeanName' is defined
Sekali lagi, Spring dengan jelas dan ringkas menunjukkan alasan kegagalan: " Tidak ada kacang bernama X yang ditentukan ".
6. Sebab: Kacang Proksi
Apabila kacang dalam konteks diproksi menggunakan mekanisme Proksi Dinamik JDK, maka proksi tidak akan memanjangkan kacang sasaran (bagaimanapun, ia akan melaksanakan antara muka yang sama).
Oleh kerana itu, jika kacang disuntikkan oleh antara muka, ia akan disambung dengan betul. Sekiranya bagaimanapun kacang disuntik oleh kelas yang sebenarnya, maka Spring tidak akan menemui definisi kacang yang sesuai dengan kelas - kerana proksi sebenarnya tidak melanjutkan kelas.
Sebab yang sangat biasa kacang mungkin diproksi adalah sokongan transaksional Spring - iaitu kacang yang diberi penjelasan dengan @Transactional .
Sebagai contoh, jika ServiceA menyuntikkan ServiceB , dan kedua-dua perkhidmatan tersebut bersifat transaksional, suntikan mengikut definisi kelas tidak akan berfungsi:
@Service @Transactional public class ServiceA implements IServiceA{ @Autowired private ServiceB serviceB; ... } @Service @Transactional public class ServiceB implements IServiceB{ ... }
Dua perkhidmatan yang sama, kali ini disuntik dengan betul oleh antara muka , akan baik-baik saja:
@Service @Transactional public class ServiceA implements IServiceA{ @Autowired private IServiceB serviceB; ... } @Service @Transactional public class ServiceB implements IServiceB{ ... }
7. Kesimpulannya
Tutorial ini membincangkan contoh kemungkinan penyebab NoSuchBeanDefinitionException biasa - dengan fokus pada bagaimana menangani pengecualian ini dalam praktik.
Pelaksanaan semua contoh pengecualian ini boleh didapati di projek GitHub - ini adalah projek berasaskan Eclipse, jadi mudah untuk diimport dan dijalankan sebagaimana adanya.
Akhirnya, senarai pengecualian dan penyelesaian penuh pada musim bunga mungkin menjadi sumber yang baik untuk menanda buku.