Seperti yang dikatakan jawaban lain, Spring hanya mengurusnya, membuat kacang dan menyuntikkannya sesuai kebutuhan.
Salah satu konsekuensinya adalah pengaturan injeksi kacang / properti mungkin terjadi dalam urutan yang berbeda dengan apa yang tampaknya disiratkan oleh file kabel XML Anda. Jadi, Anda perlu berhati-hati agar penyetel properti Anda tidak melakukan inisialisasi yang bergantung pada penyetel lain yang sudah dipanggil. Cara untuk mengatasinya adalah dengan mendeklarasikan beans sebagai implementasi InitializingBeanantar muka. Ini mengharuskan Anda untuk mengimplementasikan afterPropertiesSet()metode, dan di sinilah Anda melakukan inisialisasi kritis. (Saya juga menyertakan kode untuk memeriksa bahwa properti penting sebenarnya telah disetel.)
The pengguna Musim Semi referensi menjelaskan bagaimana dependensi melingkar diselesaikan. Kacang dibuat terlebih dahulu, lalu disuntikkan satu sama lain.
Pertimbangkan kelas ini:
package mypackage;publicclass A {public A(){System.out.println("Creating instance of A");}private B b;publicvoid setB(B b){System.out.println("Setting property b of A instance");this.b = b;}}
Dan kelas serupa B:
package mypackage;publicclass B {public B(){System.out.println("Creating instance of B");}private A a;publicvoid setA(A a){System.out.println("Setting property a of B instance");this.a = a;}}
Inilah sebabnya mengapa Spring membutuhkan konstruktor tanpa argumen ;-)
Chris Thompson
15
Tidak jika Anda menggunakan argumen konstruktor dalam definisi kacang Anda! (Tapi dalam hal ini Anda tidak dapat memiliki ketergantungan melingkar.)
Richard Fearn
1
@Richard Fearn Apakah posting Anda tentang penjelasan masalah daripada menyediakan solusi?
gstackoverflow
4
Jika Anda mencoba menggunakan injeksi konstruktor, pesan kesalahannya adalahorg.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
X. Wo Satuk
19
Dalam basis kode tempat saya bekerja (1 juta + baris kode) kami memiliki masalah dengan waktu startup yang lama, sekitar 60 detik. Kami mendapatkan 12000+ FactoryBeanNotInitializedException .
catch(BeansException ex){// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);throw ex;}
di mana destroySingleton(beanName)saya mencetak pengecualian dengan kode breakpoint bersyarat:
System.out.println(ex);returnfalse;
Rupanya ini terjadi ketika FactoryBean terlibat dalam grafik ketergantungan siklik. Kami menyelesaikannya dengan mengimplementasikan ApplicationContextAware dan InitializingBean dan menyuntikkan kacang secara manual.
Rekomendasi menarik. Rekomendasi balasan saya hanya akan melakukan itu jika Anda mencurigai bahwa referensi melingkar menyebabkan masalah kinerja. (Sayang sekali jika memecahkan sesuatu yang tidak perlu dipecahkan dengan mencoba memperbaiki masalah yang tidak perlu diperbaiki.)
Stephen C
2
Ini adalah lereng licin menuju neraka pemeliharaan untuk memungkinkan ketergantungan melingkar, mendesain ulang arsitektur Anda dari ketergantungan melingkar bisa sangat rumit, seperti dalam kasus kami. Apa yang dimaksud secara kasar bagi kami adalah kami mendapatkan koneksi database dua kali lebih banyak selama startup karena sessionfactory yang terlibat dalam dependensi melingkar. Dalam skenario lain, jauh lebih banyak bencana dapat terjadi karena kacang dibuat lebih dari 12000 kali. Tentu Anda harus menulis kacang Anda sehingga mereka mendukung penghancurannya tetapi mengapa membiarkan perilaku ini di tempat pertama?
jontejj
@jontejj, Anda berhak mendapatkan cookie
serprime
14
Masalah ->
Class A {privatefinal B b;// must initialize in ctor/instance blockpublic A(B b){this.b = b };}Class B {privatefinal A a;// must initialize in ctor/instance blockpublic B(A a){this.a = a };}
// Disebabkan oleh: org.springframework.beans.factory.BeanCurrentlyInCreationException: Kesalahan membuat kacang dengan nama 'A': Kacang yang diminta saat ini sedang dibuat: Apakah ada referensi melingkar yang tidak dapat diselesaikan?
Solusi 1 ->
Class A {private B b;public A(){};//getter-setter for B b}Class B {private A a;public B(){};//getter-setter for A a}
Solusi 2 ->
Class A {privatefinal B b;// must initialize in ctor/instance blockpublic A(@Lazy B b){this.b = b };}Class B {privatefinal A a;// must initialize in ctor/instance blockpublic B(A a){this.a = a };}
Biasanya Anda dapat mempercayai Spring untuk melakukan hal yang benar. Ini mendeteksi masalah konfigurasi, seperti referensi ke kacang yang tidak ada dan dependensi melingkar, pada waktu muat kontainer. Spring mengatur properti dan menyelesaikan dependensi selambat mungkin, ketika bean sebenarnya dibuat.
Kontainer Spring mampu menyelesaikan dependensi melingkar berbasis Setter tetapi memberikan pengecualian runtime BeanCurrentlyInCreationException dalam kasus dependensi melingkar berbasis Constructor. Dalam kasus ketergantungan melingkar berbasis Setter, kontainer IOC menanganinya secara berbeda dari skenario tipikal dimana ia akan sepenuhnya mengkonfigurasi kacang yang berkolaborasi sebelum menyuntikkannya. Misalnya, jika Bean A memiliki ketergantungan pada Bean B dan Bean B pada Bean C, penampung akan menginisialisasi C sepenuhnya sebelum menyuntikkannya ke B dan setelah B sepenuhnya diinisialisasi, wadah itu disuntikkan ke A. Tetapi dalam kasus ketergantungan melingkar, satu kacang disuntikkan ke yang lain sebelum diinisialisasi sepenuhnya.
Katakanlah A bergantung pada B, lalu Spring pertama-tama akan membuat instance A, lalu B, lalu mengatur properti untuk B, lalu mengatur B menjadi A.
Tetapi bagaimana jika B juga bergantung pada A?
Pemahaman saya adalah: Spring baru saja menemukan bahwa A telah dibangun (konstruktor dijalankan), tetapi belum sepenuhnya diinisialisasi (tidak semua injeksi dilakukan), yah, menurutnya, tidak apa-apa, lumayanlah bahwa A tidak sepenuhnya diinisialisasi, cukup setel ini tidak- instans A yang sepenuhnya diinisialisasi ke B untuk saat ini. Setelah B sepenuhnya diinisialisasi, itu ditetapkan menjadi A, dan akhirnya, A sepenuhnya dimulai sekarang.
Dengan kata lain, ini hanya mengekspos A ke B terlebih dahulu.
Untuk dependensi melalui konstruktor, Sprint hanya membuang BeanCurrentlyInCreationException, untuk menyelesaikan pengecualian ini, setel lazy-init ke true untuk kacang yang bergantung pada orang lain melalui cara konstruktor-arg.
Jika Anda umumnya menggunakan injeksi konstruktor dan tidak ingin beralih ke injeksi properti, maka injeksi metode pencarian Spring akan membiarkan satu kacang dengan malas mencari kacang lainnya dan karenanya mengatasi ketergantungan siklik. Lihat di sini: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
Injeksi Pembuat gagal ketika ada Ketergantungan Melingkar antara kacang pegas. Jadi dalam hal ini injeksi Setter kami membantu menyelesaikan masalah.
Pada dasarnya, Constructor Injection berguna untuk dependensi Wajib, untuk dependensi opsional lebih baik menggunakan injeksi Setter karena kita bisa melakukan injeksi ulang.
Jika dua biji bergantung satu sama lain maka kita tidak boleh menggunakan injeksi Pembuat di kedua definisi biji. Sebagai gantinya kita harus menggunakan injeksi penyetel di salah satu biji. (tentu saja kita dapat menggunakan injeksi penyetel pada kedua definisi kacang, tetapi injeksi konstruktor pada keduanya menampilkan 'BeanCurrentlyInCreationException'
Jawaban:
Seperti yang dikatakan jawaban lain, Spring hanya mengurusnya, membuat kacang dan menyuntikkannya sesuai kebutuhan.
Salah satu konsekuensinya adalah pengaturan injeksi kacang / properti mungkin terjadi dalam urutan yang berbeda dengan apa yang tampaknya disiratkan oleh file kabel XML Anda. Jadi, Anda perlu berhati-hati agar penyetel properti Anda tidak melakukan inisialisasi yang bergantung pada penyetel lain yang sudah dipanggil. Cara untuk mengatasinya adalah dengan mendeklarasikan beans sebagai implementasi
InitializingBean
antar muka. Ini mengharuskan Anda untuk mengimplementasikanafterPropertiesSet()
metode, dan di sinilah Anda melakukan inisialisasi kritis. (Saya juga menyertakan kode untuk memeriksa bahwa properti penting sebenarnya telah disetel.)sumber
The pengguna Musim Semi referensi menjelaskan bagaimana dependensi melingkar diselesaikan. Kacang dibuat terlebih dahulu, lalu disuntikkan satu sama lain.
Pertimbangkan kelas ini:
Dan kelas serupa
B
:Jika Anda kemudian memiliki file konfigurasi ini:
Anda akan melihat keluaran berikut saat membuat konteks menggunakan konfigurasi ini:
Perhatikan bahwa saat
a
disuntikkan keb
,a
belum sepenuhnya diinisialisasi.sumber
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Dalam basis kode tempat saya bekerja (1 juta + baris kode) kami memiliki masalah dengan waktu startup yang lama, sekitar 60 detik. Kami mendapatkan 12000+ FactoryBeanNotInitializedException .
Apa yang saya lakukan adalah menetapkan breakpoint bersyarat di AbstractBeanFactory # doGetBean
di mana
destroySingleton(beanName)
saya mencetak pengecualian dengan kode breakpoint bersyarat:Rupanya ini terjadi ketika FactoryBean terlibat dalam grafik ketergantungan siklik. Kami menyelesaikannya dengan mengimplementasikan ApplicationContextAware dan InitializingBean dan menyuntikkan kacang secara manual.
Ini memotong waktu startup menjadi sekitar 15 detik.
Jadi jangan selalu berasumsi bahwa musim semi bisa menjadi solusi yang baik untuk memecahkan referensi ini untuk Anda.
Untuk alasan ini saya merekomendasikan untuk menonaktifkan resolusi ketergantungan siklik dengan AbstractRefreshableApplicationContext # setAllowCircularReferences (false) untuk mencegah banyak masalah di masa mendatang.
sumber
Masalah ->
// Disebabkan oleh: org.springframework.beans.factory.BeanCurrentlyInCreationException: Kesalahan membuat kacang dengan nama 'A': Kacang yang diminta saat ini sedang dibuat: Apakah ada referensi melingkar yang tidak dapat diselesaikan?
Solusi 1 ->
Solusi 2 ->
sumber
Itu hanya melakukannya. Ini membuat instance
a
danb
, dan menyuntikkan masing-masing satu sama lain (menggunakan metode penyetelnya).Apa masalahnya?
sumber
Dari Referensi Musim Semi :
sumber
Kontainer Spring mampu menyelesaikan dependensi melingkar berbasis Setter tetapi memberikan pengecualian runtime BeanCurrentlyInCreationException dalam kasus dependensi melingkar berbasis Constructor. Dalam kasus ketergantungan melingkar berbasis Setter, kontainer IOC menanganinya secara berbeda dari skenario tipikal dimana ia akan sepenuhnya mengkonfigurasi kacang yang berkolaborasi sebelum menyuntikkannya. Misalnya, jika Bean A memiliki ketergantungan pada Bean B dan Bean B pada Bean C, penampung akan menginisialisasi C sepenuhnya sebelum menyuntikkannya ke B dan setelah B sepenuhnya diinisialisasi, wadah itu disuntikkan ke A. Tetapi dalam kasus ketergantungan melingkar, satu kacang disuntikkan ke yang lain sebelum diinisialisasi sepenuhnya.
sumber
Katakanlah A bergantung pada B, lalu Spring pertama-tama akan membuat instance A, lalu B, lalu mengatur properti untuk B, lalu mengatur B menjadi A.
Tetapi bagaimana jika B juga bergantung pada A?
Pemahaman saya adalah: Spring baru saja menemukan bahwa A telah dibangun (konstruktor dijalankan), tetapi belum sepenuhnya diinisialisasi (tidak semua injeksi dilakukan), yah, menurutnya, tidak apa-apa, lumayanlah bahwa A tidak sepenuhnya diinisialisasi, cukup setel ini tidak- instans A yang sepenuhnya diinisialisasi ke B untuk saat ini. Setelah B sepenuhnya diinisialisasi, itu ditetapkan menjadi A, dan akhirnya, A sepenuhnya dimulai sekarang.
Dengan kata lain, ini hanya mengekspos A ke B terlebih dahulu.
Untuk dependensi melalui konstruktor, Sprint hanya membuang BeanCurrentlyInCreationException, untuk menyelesaikan pengecualian ini, setel lazy-init ke true untuk kacang yang bergantung pada orang lain melalui cara konstruktor-arg.
sumber
Ini dijelaskan dengan jelas di sini . Terima kasih kepada Eugen Paraschiv.
Ketergantungan melingkar adalah bau desain, baik perbaiki atau gunakan @Lazy untuk ketergantungan yang menyebabkan masalah untuk mengatasinya.
sumber
Jika Anda umumnya menggunakan injeksi konstruktor dan tidak ingin beralih ke injeksi properti, maka injeksi metode pencarian Spring akan membiarkan satu kacang dengan malas mencari kacang lainnya dan karenanya mengatasi ketergantungan siklik. Lihat di sini: http://docs.spring.io/spring/docs/1.2.9/reference/beans.html#d0e1161
sumber
Injeksi Pembuat gagal ketika ada Ketergantungan Melingkar antara kacang pegas. Jadi dalam hal ini injeksi Setter kami membantu menyelesaikan masalah.
Pada dasarnya, Constructor Injection berguna untuk dependensi Wajib, untuk dependensi opsional lebih baik menggunakan injeksi Setter karena kita bisa melakukan injeksi ulang.
sumber
Jika dua biji bergantung satu sama lain maka kita tidak boleh menggunakan injeksi Pembuat di kedua definisi biji. Sebagai gantinya kita harus menggunakan injeksi penyetel di salah satu biji. (tentu saja kita dapat menggunakan injeksi penyetel pada kedua definisi kacang, tetapi injeksi konstruktor pada keduanya menampilkan 'BeanCurrentlyInCreationException'
Lihat dokumen Spring di " https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#resources-resource "
sumber