Spring memiliki solusi sendiri untuk ketergantungan melingkar antara kacang. Titik kuncinya adalah cache level tiga. Tentu saja, solusi ini tidak dapat menyelesaikan semua masalah, ia hanya dapat menyelesaikan ketergantungan melingkar non-konstruktor dalam mode Singleton Bean.
Kita akan mulai dari urutan inisialisasi A-> B-> CA, yang berarti bahwa contoh B diperlukan dalam kacang A, contoh C diperlukan dalam kacang B, contoh A diperlukan dalam kacang C, dan contoh A diperlukan dalam kacang C. Tentu saja, kebutuhan ini bukanlah ketergantungan seperti konstruktor. Setelah prasyarat tersedia, kita bisa memulai. Tidak ada keraguan bahwa kami akan menginisialisasi yang pertama. Metode inisialisasi adalah org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
Dilindungi <T> t doGetBean (nama string akhir, kelas akhir <t> wajib, objek akhir [] args, boolean typecheckonly) melempar beansException {final string beanname = transformedBeanName (name); Kacang objek; // Periksa Singleton Cache dengan penuh semangat untuk singleton yang terdaftar secara manual. Objek sharedInstance = getsingleton (beanname); // Fokus 1 if (sharedInstance! = Null && args == null) {if (logger.isdebugeNabled ()) {if (issingletCureRently increation (beanname)) {logger.debug ("Konsekuensi yang dikembalikan dengan penuh semangat" tidak dikembalikan dari sunleton bean '" + not -cache." referensi"); } else {logger.debug ("instance pengembalian singleton bean '" + beanname + "'"); }} bean = getObjectForBeanInstance (sharedInstance, name, beanname, null); } else {// gagal jika kita sudah membuat instance kacang ini: // kita diasumsikan dalam referensi melingkar. if (isPrototypeCurseCreation (beanname)) {lempar beanCurrently increationexception (beanname); } // Periksa apakah ada definisi kacang di pabrik ini. BeanFactory ParentBeanFactory = getParentBeanFactory (); if (parentBeanFactory! = null &&! containsbeandefinition (beanname)) {// tidak ditemukan -> periksa induk. String nametolookup = originalBeanName (name); if (args! = null) {// delegasi untuk orang tua dengan args eksplisit. return (t) parentBeanFactory.getBean (nametolookup, args); } else {// no args -> delegasi ke metode Getbean standar. return ParentBeanFactory.getBean (nametolookup, wajib diminta); }} if (! TypeCheckOnly) {MarkBeanaScreated (beanname); } coba {final rootbeandefinition mbd = getmergedlocalbeandefinition (beanname); checkmergedbeandefinition (MBD, beanname, args); // menjamin inisialisasi kacang yang diandalkan kacang saat ini. String [] dependson = mbd.getDependson (); if (dependentson! = null) {for (string dependSonBean: dependSon) {if (isDependent (beanname, dependSonBean)) {lempar beanCreationException baru (mbd.getResourcedescription (), beanname, "Circulared-on-on-one-on '" + beanName + "' dan 'dan'" + "" "" "" "" "" "" " +" "dan beanName +" 'dan beanname, "Circulare); } RegisterDependentBean (DependentSonbean, Beanname); getbean (DigenTonsonbean); }} // Buat instance bean. if (mbd.issingleton ()) {// concern 2 sharedInstance = getSingleton (beanname, objek baru <bestigasi> () {@Override Objek getObject () melempar beansexception {try {return create (beanname, mbd, args);} cacan {return {beane (beanccice /beanname, mbd, args);} Catchone (return {itseACE (mbd, mbd, args);} Catchon (return {iNeEke (mbd, mbd, args);} Catchone (itscecing {itseACHECE (MBD, MBD, ARGS);} COCKICE ( mungkin telah ditempatkan di sana // dengan penuh semangat dengan proses pembuatan, untuk memungkinkan resolusi referensi melingkar. bean = getObjectForBeanInstance (sharedInstance, name, beanname, mbd); } else if (mbd.isprototype ()) {// Ini adalah prototipe -> Buat instance baru. Objek prototipeInstance = null; coba {beforeprototypeCreation (beanname); prototipeInstance = createBean (beanname, mbd, args); } akhirnya {afterprototypeCreation (beanname); } bean = getObjectForBeanInstance (prototipeInstance, name, beanname, mbd); } else {string scopename = mbd.getscope (); scope final scope = this.scopes.get (scopename); if (scope == null) {lempar baru ilegalstateException ("Tidak ada lingkup terdaftar untuk nama lingkup '" + scopename + "'"); } coba {objek scopedInstance = scope.get (beanname, new ObjectFactory <Peject> () {@Override Objek getObject () melempar beansException {beforeprototypecreation (beanname); coba {return createBean (beanName, mbd, argeeance (arger); {return createBean (beanName, mbd, mbd, arger); {return createBean (beanName, mbd, mbd, argeon); oMeryproteon (beanname, mbd, args); {{beanname, mbd, mbd, argeon); }}); bean = getObjectForBeanInstance (ScopedInstance, Name, Beanname, MBD); } catch (ilegalstateException ex) {lempar beanCreationException baru (beanname, "scope '" + scopename + "' tidak aktif untuk utas saat ini; pertimbangkan" + "mendefinisikan proxy yang dilingkupkan untuk kacang ini jika Anda ingin merujuknya dari singleton", ex); }}} catch (beansException ex) {cleanupafterbeanceReationFailure (beanname); lempar ex; }} // Periksa apakah jenis yang diperlukan cocok dengan jenis instance kacang yang sebenarnya. if (wajib diperlukan! = null && bean! = null &&! wajib. } catch (TypeMisMatchException ex) {if (logger.isdebugeNabled ()) {logger.debug ("Gagal mengonversi kacang '" + nama + "' menjadi tipe yang diperlukan [" + classutils.getqualifiedName (wajib) + "]", ex); } lempar beannotofrequiredtypeException baru (name, wajib, bean.getClass ()); }} return (t) bean; } Metode ini sangat panjang, mari kita bicarakan sedikit demi sedikit. Mari kita lihat fokus kita dulu. Object sharedInstance = getSingleton(beanName ) memperoleh objek singleton dari koleksi singleton berdasarkan namanya. Mari kita lihat metode ini, dan akhirnya org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
objek yang dilindungi getseTon (string beanname, boolean weolylyreference) {objek singletonobject = this.singletonobjects.get (beanname); if (singletonObject == null && issingletonCureRentlycreation (beanname)) {disinkronkan (this.singletonObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && owolearlyreference) {objectFactory <?> singletonfactory = this.singletonfactory.get (beanname); if (singletonfactory! = null) {singletonObject = singletonfactory.getObject (); this.earlysingletonObjects.put (beanname, singletonObject); this.singletonfactory.remove (beanname); }}} return (singletonObject! = null_object? singletonObject: null); } Setiap orang harus memperhatikan metode ini, ini sangat penting. Kami menyebutkan cache Level 3 di awal, dan salah satu titik penggunaan ada di sini. Cache level 3 mana? singletonObjects dari cache tingkat pertama ditempatkan dengan singletonObjects instantiated. Tingkat kedua earlySingletonObjects menyimpan objek singleton yang diekspos sebelumnya (tidak sepenuhnya dirakit). Singletonfactories tingkat ketiga menyimpan pabrik objek objek yang akan dipakai. Setelah menjelaskan cache Level 3, mari kita lihat logikanya. Pertama kali saya datang di this.singletonObjects.get(beanName) mengembalikan nol. Kemudian isSingletonCurrentlyInCreation menentukan apakah data dapat diperoleh dalam cache sekunder.
public boolean issingleTonCureScreation (string beanname) {return this.singletonscureReCreation.contains (beanname); } Apakah Beanname dimasukkan dalam set singletonsCurrentlyInCreation berisi nama beanname yang masuk? Tidak ada tempat untuk mengaturnya sebelumnya, jadi pasti tidak termasuk itu. Oleh karena itu, metode ini mengembalikan false, dan proses selanjutnya tidak akan ditinggalkan. Metode getSingleton mengembalikan nol.
Mari kita lihat fokus 2. Ini juga merupakan getSingleton , tetapi ini adalah proses nyata menciptakan kacang. Kita dapat melihat bahwa objek ObjectFactory anonim diteruskan. Metode GetObject yang disebut CreateBean, metode nyata untuk membuat kacang. Tentu saja kita bisa mengesampingkannya dan terus melihat metode getSingleton kita
Objek publik getingleton (string beanname, objectFactory <?> singletonfactory) {assert.notnull (beanname, "'beanname' tidak boleh null"); disinkronkan (this.singletonObjects) {objek singletonobject = this.singletonobjects.get (beanname); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isdebugeNabled ()) {logger.debug ("Membuat contoh bersama kacang singleton '" + beanname + "'"); } beFesingLeTonCreation (beanname); boolean newsleton = false; Boolean RecordsuppressExceptions = (this.suppressEcceptions == null); if (recordsuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet <Ecleption> (); } coba {singletonObject = singletonfactory.getObject (); newsingleton = true; } Catch (IllegalStateException Ex) {// Memiliki objek singleton secara implisit muncul sementara itu -> // jika ya, lanjutkan karena pengecualian menunjukkan keadaan itu. singletonObject = this.singletonobjects.get (beanname); if (singletonObject == null) {throw ex; }} catch (BeanCreationException ex) {if (recordsuppressedExceptions) {for (Exception SuppressException: this.suppressedExceptions) {ex.addrelatedCause (SuppressedException); }} lempar ex; } akhirnya {if (recordsuppressedExceptions) {this.suppressedExceptions = null; } aftersingletonCreation (beanname); } if (newsingleton) {addsingleton (beanname, singletonObject); }} return (singletonObject! = null_object? singletonObject: null); }} Kalimat pertama dari Object singletonObject = this.singletonObjects.get(beanName) mengambil data dari cache tingkat pertama, yang pasti nol. Metode beforeSingletonCreation kemudian dipanggil.
void yang dilindungi beforesingletonCreation (string beanname) {if (! this.increationCheckexclusions.contains (beanname) &&! this.singletonscureScureScreation.add (beanname)) {lempar beanCurrentle increation exception (beanname)) {beancurrentle increation exception (beanname)) {beanCurrentle increation exception (beanname)) {beanCurrentle increation exception (beanname) (beanName; }} Di antara mereka adalah proses menambahkan beanname ke set singletonsCurrentlyInCreation . Set ini sangat penting dan akan digunakan nanti. Kemudian, panggil metode getObject singletonfactory untuk melakukan proses penciptaan nyata. Mari kita lihat proses penciptaan nyata yang disebutkan di atas createBean Logika inti di dalamnya adalah doCreateBean .
Objek Dilindungi DocreateBean (Final String Beanname, Final RootBeandefinition MBD, Objek akhir [] args) {// Instantiate bean. Beanwrapper instanceWrapper = null; if (mbd.issingleton ()) {instanceWrapper = this.factorybeaninstancecache.remove (beanname); } if (instanceWrapper == null) {instanceWrapper = createBeanInstance (beanname, mbd, args); } objek akhir bean = (instanceWrapper! = null? instanceWrapper.getWrappedInstance (): null); Kelas <?> beantype = (instanceWrapper! = Null? InstanceWrapper.getWrappedClass (): null); // Izinkan post-prosesor untuk memodifikasi definisi kacang gabungan. disinkronkan (mbd.postprocessinglock) {if (! mbd.postprocessed) {applyMergedBeandefinitionPostProcessors (MBD, beantype, beanname); mbd.postprocessed = true; }} // Singleton cache yang penuh semangat untuk dapat menyelesaikan referensi melingkar // bahkan ketika dipicu oleh antarmuka siklus hidup seperti BeanfactoryAware. // Concern3 Boolean EarlySingLeTonexPosure = (mbd.issingleton () && this.allowcircularReferences && issingletonCureRentlycreation (beanname)); if (EarlySingLeTonExPosure) {if (logger.isdebugeNabled ()) {logger.debug ("kacang yang di -cache '" + beanname + "' untuk memungkinkan penyelesaian referensi sirkular potensial"); } AddSingLeTonFactory (beanname, ObjectFactory baru <POMPERTIF> () {@Override Objek publik getObject () melempar BeansException {return getearlyBeanReference (beanname, mbd, bean);}}); } // Inisialisasi instance bean. Object ExposedObject = Bean; coba {populeBean (beanname, mbd, instanceWrapper); if (ExposedObject! = NULL) {ExposedObject = initializeBean (beanname, ExposedObject, MBD); }} catch (throwable ex) {if (ex instance dari beanCreationException && beanname.equals (((beancreationexception) ex) .getBeanName ())) {throw (beanscreationexception) ex; } else {throw new BeancreationException (mbd.getResourcedescription (), beanname, "inisialisasi kacang gagal", ex); }} if (EarlySingLeTonExPosure) {Object EarlySingLeTonReference = getsingleton (beanname, false); if (EarlySingLeTonReference! = null) {if (ExposedObject == bean) {ExposedObject = EarlySingLeTonReference; } lain if (! this.allowrawinjectionDespitewrapping && hasDependentBean (beanName)) {string [] dependentBeans = getDependentBeans (beanName); Atur <string> AcctualDependentBeans = new LinkedHashset <Rips> (dependentBeans.length); untuk (String DependentBean: DependentBeans) {if (! RemovesingLeTonifCreatedForPecheckOnly (dependentBean)) {AcctualDependentBeans.add (dependentBean); }} if (! AcctualDependentBeans.isempty ()) {lempar beanCurrelently increationexception (beanname, "bean with name '" + beanname + "' telah disuntikkan ke dalam kacang -kacangan lainnya,"), ")," Wr. Ini berarti bahwa kacang lain tidak menggunakan versi final dari kacang " +". }}}}} // Daftarkan kacang sebagai sekali pakai. coba {registerDispoBeBeanifNecessary (beanname, bean, mbd); } catch (beandefinitionValidationException ex) {throw new BeancreationException (mbd.getResourcedescription (), beanname, "tanda tangan penghancuran tidak valid", ex); } return ExposedObject; } createBeanInstance membuat objek menggunakan refleksi. Mari kita lihat nilai atribut Poin 3 Juri earlySingletonExposure . Salah satu poin penilaian isSingletonCurrentlyInCreation(beanName)
public boolean issingleTonCureScreation (string beanname) {return this.singletonscureReCreation.contains (beanname); } Saya menemukan bahwa set SingletonscureRanderCreation digunakan. Beanname telah diisi dalam langkah -langkah di atas, sehingga dapat ditemukan. Oleh karena itu, properti earlySingletonExposure ditentukan untuk menjadi benar dalam kombinasi dengan kondisi lain, dan proses berikut ditambahkan addSingletonFactory . Berikut adalah pabrik objek yang sesuai dengan beanname (a). Implementasi metode getObject -nya dicapai melalui metode getEarlyBeanReference . Pertama, mari kita lihat implementasi AddSingLeTonfactory
void yang dilindungi addsingletonfactory (string beanname, objectFactory <?> singletonfactory) {assert.notnull (singletonfactory, "pabrik singleton tidak boleh nol"); disinkronkan (this.singletonObjects) {if (! this.singletonObjects.containskey (beanname)) {this.singletonfactory.put (beanname, singletonfactory); this.earlysingletonobjects.remove (beanname); this.registeredsingletons.add (beanname); }}} Menyimpan data ke level ketiga cache singletonfactories, membersihkan data cache tingkat kedua berdasarkan beanname. Ada poin yang sangat penting di sini, yaitu untuk mengatur nilai ke dalam cache tingkat ketiga, yang merupakan titik inti dari pemrosesan dependensi melingkar musim semi. Metode getEarlyBeanReference adalah implementasi GetObject. Dapat dengan mudah dipertimbangkan bahwa ia mengembalikan instance objek yang diisi dengan A. Setelah mengatur cache Level 3, proses mengisi sifat -sifat objek A dimulai. Deskripsi berikut tidak memiliki permintaan kode sumber, hanya pengantar singkat.
Saat mengisi A, saya menemukan bahwa kacang tipe B diperlukan, jadi saya terus memanggil metode Getbean untuk membuatnya. Proses memori persis sama dengan di atas. Kemudian saya pergi ke proses mengisi kacang tipe C, dan panggilan yang sama Getbean (C) dipanggil untuk dieksekusi. Saat mengisi properti A, saya menelepon Getbean (A). Mari kita lanjutkan dari sini bahwa saya memanggil Object sharedInstance = getSingleton(beanName), kode yang sama, tetapi logika pemrosesan sangat berbeda.
objek yang dilindungi getseTon (string beanname, boolean weolylyreference) {objek singletonobject = this.singletonobjects.get (beanname); if (singletonObject == null && issingletonCureRentlycreation (beanname)) {disinkronkan (this.singletonObjects) {singletonObject = this.earlysingletonObjects.get (beanname); if (singletonObject == null && owolearlyreference) {objectFactory <?> singletonfactory = this.singletonfactory.get (beanname); if (singletonfactory! = null) {singletonObject = singletonfactory.getObject (); this.earlysingletonObjects.put (beanname, singletonObject); this.singletonfactory.remove (beanname); }}} return (singletonObject! = null_object? singletonObject: null); } Namun, objek diperoleh dari singletonObjects tidak dapat diperoleh. Karena A berada di set singletonsCurrentlyInCreation , ia memasuki logika berikut, dan mengambilnya dari Cache earlySingletonObjects tingkat kedua, tetapi masih belum ditemukan. Kemudian dia menemukan pabrik objek yang sesuai dari cache level singletonFactories Panggil metode getObject untuk mendapatkan objek instan dari A yang belum sepenuhnya diisi, dan kemudian menghapus data cache tingkat ketiga, mengisi data cache tingkat kedua, dan mengembalikan objek ini A. C tergantung pada pengisian instance A, meskipun A ini tidak lengkap. Tidak peduli bagaimana pengisian gaya-C selesai, Anda dapat menempatkan C di singletonObjects cache tingkat pertama dan membersihkan data cache tingkat kedua dan tingkat ketiga pada saat yang sama. Dalam proses yang sama, jika C tergantung pada B diisi, B diisi. Demikian pula, jika B tergantung pada A diisi, A diisi. Beginilah cara pegas memecahkan referensi melingkar.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.