الربيع له حله الخاص للتبعيات الدائرية بين الفاصوليا. النقطة الرئيسية هي المستوى الثالث ذاكرة التخزين المؤقت. بالطبع ، لا يمكن لهذا الحل حل جميع المشكلات ، بل يمكنه حل الاعتماد الدائري فقط لغير البترات في وضع الفول المفرد.
سنبدأ من ترتيب التهيئة لـ A-> B-> CA ، مما يعني أن هناك حاجة إلى حالات B في حبة A ، هناك حاجة إلى مثيلات C في حبة B ، ومثيلات A مطلوبة في حبة C ، وأن حالات A مطلوبة في حبة C. بالطبع ، هذه الحاجة ليست تبعية مثل البناء. بمجرد توفر المتطلبات المسبقة ، يمكننا أن نبدأ. ليس هناك شك في أننا سنقوم بتهيئة أولاً. طريقة التهيئة هي org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
محمية <T> t doggeBean (اسم السلسلة النهائية ، الفئة النهائية <T> مطلوبة ، الكائن النهائي [] args ، boolean typecheckonly) يلقي beansexception {Final String beanname = transformedBeanName (name) ؛ كائن الفول // تحقق بفارغ الصبر من ذاكرة التخزين المؤقت Singleton لـ Singletons المسجلة يدويًا. كائن مشترك = getSingleton (Beanname) ؛ // Focus 1 if (sharedInstance! = null && args == null) {if (logger.isdebugenabled ()) {if (issingletoncurrallyincreation (beanname)) {logger.deBug ("الإشارة إلى الفول المفرد بفارغ الصبر" + beanname + ". } else {logger.debug ("مثيل عودة مخبأة من Singleton Bean '" + Beanname + "'") ؛ }} bean = getObjectForBeaninStance (sharedInstance ، name ، beanname ، null) ؛ } آخر {// تفشل إذا كنا بالفعل قم بإنشاء مثيل الفول هذا: // نحن افتراض ضمن مرجع دائري. if (isProtypeCurlyIncreation (beanname)) {رمي جديد beancurerlyincreationException (beanname) ؛ } // تحقق مما إذا كان تعريف الفول موجودًا في هذا المصنع. Beanfactory ParentBeanFactory = getParentBeanFactory () ؛ if (parentBeanFactory! = null &&! containsbeandefinition (beanname)) {// غير موجود -> تحقق من الأصل. سلسلة nametolookup = OriginalBeanName (الاسم) ؛ if (args! = null) {// devation to parent مع args صريحة. إرجاع (t) parentbeanfactory.getBean (nametolookup ، args) ؛ } آخر {// لا args -> تفويض إلى طريقة getBean القياسية. إرجاع ParentBeanfactory.getBean (nametolookup ، مطلوبة stype) ؛ }} if (! typecheckonly) {markBeanAscreated (beanname) ؛ } جرب {Final RootBeanDefinition mbd = getMergedLocalBeanDefinition (beanname) ؛ checkmergedbeandefinition (MBD ، Beanname ، args) ؛ // ضمان تهيئة الفاصوليا التي يعتمد عليها الفول الحالي. String [] depresson = mbd.getDependson () ؛ إذا كان (Conterentson! = null) {for (string depondsonbean: drepson) {if (isDender (beanname ، reparsonbean)) {رمي beancreationException (mbd.getResourcedescription () ، beanname ، "يعتمد على العلاقة بين" + beanname + "و" + deponbean + "") ؛ } registerDependentBean (centerentsonbean ، beanname) ؛ getBean (centerentsonbean) ؛ }} // إنشاء مثيل بين الفول. if (mbd.issingleton ())) {// الاهتمام 2 sharedInstance = getSingleton (beanname ، ObjectFactory new <bounge> () {Override public object getObject () remsexception {try {return createbean (beanname ، mbd ، args) ؛ / Bean = getObjectForBeanInstance (sharedInstance ، name ، Beanname ، MBD) ؛ } آخر إذا (mbd.isprototype ()) {// إنه نموذج أولي -> إنشاء مثيل جديد. Object OrityOnstance = null ؛ جرب {قبل النموذج النموذجي (beanname) ؛ النموذج الأولي intractance = createBean (beanname ، mbd ، args) ؛ } أخيرًا {efterPrototypecreation (beanname) ؛ } bean = getObjectForBeanInstance (النموذج الأولي ، الاسم ، beanname ، mbd) ؛ } آخر {String scopename = mbd.getScope () ؛ نطاق النطاق النهائي = this.scopes.get (scopename) ؛ if (Scope == NULL) {رمي جديد alficalStateException ("لا يوجد نطاق مسجل لاسم النطاق '" + scopename + "' ') ؛ } جرب {Object scopedInstance = scope.get (beanname ، ObjectFactory <object> () {Override الكائن العام getObject () يلقي beansexception {قبل protototypecreation (beanname) ؛ try {return createbean (beanname ، mbd ، args) ؛} أخيرًا {afterprototypecreation (}}} ؛ Bean = getObjectForBeanInstance (ScopedInstance ، name ، Beanname ، MBD) ؛ } catch (alfortalstateException ex) {رمي beancreationException (beanname ، "النطاق" " + scopename +" "غير نشط للخيط الحالي ؛ فكر" + "تحديد وكيل محدد لهذا الفول إذا كنت تنوي الإشارة إليه من المفرد" ، السابقين) ؛ }}} catch (beansexception ex) {cleanupAfterBeanCreationFailure (beanname) ؛ رمي السابقين }} // تحقق من أن النوع المطلوب يطابق نوع مثيل الفول الفعلي. if (requiretType! = null && bean! = null &&! requiretType.ISAssignableFrom (bean.getClass ()))) {try {return gettypeconverter (). } catch (typemismatchException ex) {if (logger.isdebugenabled ()) {logger.debug ("فشل في تحويل الفول" + اسم + "إلى النوع المطلوب [ } رمي beannotofrequiredtypeexception (الاسم ، المطلوبة ، bean.getclass ()) ؛ }} return (t) Bean ؛ } هذه الطريقة طويلة جدًا ، دعنا نتحدث عنها شيئًا فشيئًا. دعونا نلقي نظرة على تركيزنا أولاً. يحصل Object sharedInstance = getSingleton(beanName ) على كائن Singleton من مجموعة من Singletons استنادًا إلى الاسم. دعونا نلقي نظرة على هذه الطريقة ، وأخيرا org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
كائن محمي getSingleton (سلسلة beanname ، boolean allearyrelyReference) {object singletOnObject = this.singletonobjects.get (beanname) ؛ if (singletOnObject == null && issingletoncurrallyincreation (beanname)) {synchronized (this.singletonObjects) {singletonobject = this.earlysingletonobjects.get (beanname) ؛ if (singletOnObject == null && allearyreference) {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) ؛ } يجب على الجميع الانتباه إلى هذه الطريقة ، إنه أمر مهم للغاية. ذكرنا ذاكرة التخزين المؤقت من المستوى 3 في البداية ، وأحد نقاط الاستخدام هنا. أي ذاكرة التخزين المؤقت من المستوى 3 هي؟ يتم وضع singletonObjects من ذاكرة التخزين المؤقت من المستوى الأول مع instantized singletonobjects. المستوى الثاني earlySingletonObjects من ايترنجليتونوب كائنات singleton التي تعرضت مسبقا (لا يتم تجميعها بالكامل). تخزن SingletonFactories من المستوى الثالث مصنع الكائن الذي سيتم إنشاء مثيل له. بعد شرح ذاكرة التخزين المؤقت من المستوى 3 ، دعونا نلقي نظرة على المنطق. في المرة الأولى التي أتيت فيها إلى this.singletonObjects.get(beanName) . ثم يحدد isSingletonCurrentlyInCreation ما إذا كان يمكن الحصول على البيانات في ذاكرة التخزين المؤقت الثانوية.
Boolean public issingletoncurrallyincreation (سلسلة beanname) {return this.singletnscurserightincreation.contains (beanname) ؛ } هل يتم تضمين اسم Beanname في مجموعة singletonsCurrentlyInCreation يحتوي على اسم Beanname القادم؟ لا يوجد مكان لضبطه من قبل ، لذلك بالتأكيد لا يشمله. لذلك ، تُرجع هذه الطريقة خطأ ، ولن تترك العملية اللاحقة. طريقة getSingleton إرجاع فارغة.
دعونا نلقي نظرة على التركيز 2. إنه أيضًا getSingleton ، ولكنها العملية الحقيقية لإنشاء فول. يمكننا أن نرى أنه يتم تمرير كائن كائن مجهول. بالطبع يمكننا وضعه جانباً والاستمرار في النظر إلى طريقة getSingleton
getSingleton الكائن العام (سلسلة beanname ، ObjectFactory <؟> singletonfactory) {assert.notnull (beanname ، "beanname" يجب ألا يكون فارغًا ") ؛ synchronized (this.singletOnObjects) {object singletOnObject = this.singletOnObjects.get (beanname) ؛ if (singletOnObject == null) {if (this.singletlectongructuregruction) {رمي جديد beancreationNotallowedException (Beanname ، "Singleton Bean Creation غير مسموح به بينما يكون المفرد في هذا المصنع في الدمار" + "(لا تطلب الفاصوليا من الفاصوليا في طريقة تدمير!)") ") ؛ } if (logger.isdebugenabled ()) {logger.debug ("إنشاء مثيل مشترك لـ Singleton Bean '" + beanname + "'") ؛ } be ForresingleToncreation (beanname) ؛ Boolean Newsingleton = false ؛ Boolean RecordsupressedExceptions = (this.suappressedExceptions == null) ؛ if (RecorductionExceptions) {this.suappressedExceptions = new LinkedHashSet <Sentive> () ؛ } حاول {singletOnObject = singletonfactory.getObject () ؛ Newsingleton = صحيح ؛ } catch (alfortalstateException ex) {// قد ظهر كائن Singleton ضمنيًا في هذه الأثناء -> // إذا كانت الإجابة بنعم ، تابعه لأن الاستثناء يشير إلى تلك الحالة. singletOnObject = this.singletonobjects.get (beanname) ؛ if (singletonObject == null) {throw ex ؛ }} catch (beancreationException ex) {if (regustUappressedExceptions) {for (استثناء قمعي: هذا. }} رمي السابقين ؛ } أخيرًا {if (regustUappressedExceptions) {this.suappressedExceptions = null ؛ } efrsingletoncreation (beanname) ؛ } if (newsingleton) {addSingleton (beanname ، singletonObject) ؛ }} return (singletOnObject! = null_object؟ singletOnObject: null) ؛ }} الجملة الأولى من هذه الطريقة Object singletonObject = this.singletonObjects.get(beanName) تجلب بيانات من ذاكرة التخزين المؤقت من المستوى الأول ، والتي هي بالتأكيد لاغية. ثم يتم استدعاء طريقة beforeSingletonCreation .
void be forsingletoncreation (سلسلة beanname) {if (! this.increationCheCkexClusions.contains (beanname) &&! this.singletlectincurblyincreation.add (beanname)) }} من بينها عملية إضافة Beanname إلى مجموعة singletonsCurrentlyInCreation . هذه المجموعة مهمة للغاية وسيتم استخدامها لاحقًا. ثم ، اتصل بطريقة getObject لـ SingletonFactory لأداء عملية الإنشاء الحقيقية. دعونا نلقي نظرة على عملية الإنشاء الحقيقية المذكورة أعلاه createBean المنطق الأساسي بداخله هو doCreateBean .
كائن محمي docreatebean (سلسلة beanname النهائية ، RootBeanDefinition MBD ، الكائن النهائي [] args) {// instantiate the Bean. beanwrapper مثيل reclapper = null ؛ if (mbd.issingleton ()) {eastywrapper = this.factoryBeanInstancecache.Remove (beanname) ؛ } if (eCHATIONWRAPPER == NULL) {aluteWrapper = createBeaninStance (beanname ، mbd ، args) ؛ } الكائن النهائي Bean = (eCHATIONWRAPPER! = null؟ aluteWrapper.getWrappedInStance (): null) ؛ الفئة <؟> beantype = (almatewrapper! = null؟ aluteWrapper.getWrappedClass (): null) ؛ // السماح لما بعد المعالجات بتعديل تعريف الفول المدمج. Synchronized (MBD.PostProcessinglock) {if (! mbd.postprocound) {ardmergedBeanDefinitionPostProcsors (MBD ، Beantype ، beanname) ؛ mbd.postprocorted = true ؛ }} // ذاكرة التخزين المؤقت بفارغ الصبر لتكون قادرة على حل المراجع الدائرية // حتى عندما يتم تشغيلها بواسطة واجهات دورة الحياة مثل beanfactoryaware. . if (اوكرنغليتونيكبوس) {if (logger.isdebugenabled ()) {logger.debug ("Bean cached بفارغ الصبر" + beanname + "'للسماح بحل المراجع الدائرية المحتملة") ؛ } addsingletonfactory (beanname ، ObjectFactory <bomf> () {Override Public Object GetObject () يلقي beansexception {return getearlybeanreference (beanname ، mbd ، bean) ؛}}) ؛ } // تهيئة مثيل الفول. الكائن المعرض exposedObject = Bean ؛ حاول {populateBean (beanname ، mbd ، eChateWrapper) ؛ if (exposedObject! = null) {exposedObject = initializeBean (beanname ، exposedObject ، mbd) ؛ }} catch (throwable ex) {if (ex extuteof beancreationException && beanname.equals (((beancreationException) ex) .getBeanName ())) } آخر {رمي جديد beancreationException (mbd.getResourCedescription () ، beanname ، "تهيئة الفول فشل" ، ex) ؛ }} if (ariOmSingLetOnexposure) {Object ariatsingleTonReference = getSingleton (beanname ، false) ؛ if (اوكرنغليتونري! = null) {if (exposedObject == Bean) {exposedObject = اوكرنغليتونري ؛ } آخر إذا (! this.allowRawInjectionDespItEwRapping && hasdependentbean (beanname)) {string [] ceneralbeans = getDependentBeans (beanname) ؛ SET <Tring> agauldependentBeans = New LinkedHashSet <String> (ArendenceBeans.Length) ؛ لـ (string arendenbean: arendenceBeans) {if (! removesingletonifcreatevEdupeCheckOnly (reledenceBean)) {stuterpendentbeans.add (arendenceBean) ؛ }}} إذا (! الفعلي denespenderbeans.isempty ()) {رمي جديد beancurrallyincreationException (beanname ، "bean with name '" + beanname + "' تم حقنه في الفاصوليا الأخرى [" + stringutils.collectionTocomaDeLimitedStr لا تستخدم الفاصوليا الأخرى الإصدار النهائي من " +" فول. }}}}} // تسجيل الفول على أنه يمكن التخلص منه. حاول {registerDisposableBeanifnecessary (Beanname ، Bean ، MBD) ؛ } catch (BeanDefinitionValidationException ex) {رمي جديد beancreationException (mbd.getResourcedescription () ، beanname ، "توقيع الدمار غير الصالح" ، EX) ؛ } إرجاع مكشوفة ؛ } createBeanInstance ينشئ كائن باستخدام الانعكاس. دعنا نلقي نظرة على قيمة السمة في نقطة التحكيم 3 earlySingletonExposure . واحدة من نقاط الحكم isSingletonCurrentlyInCreation(beanName)
Boolean public issingletoncurrallyincreation (سلسلة beanname) {return this.singletnscurserightincreation.contains (beanname) ؛ } لقد وجدت أن مجموعة Singletncurbyincreation تستخدم. تم ملء اسم Beanname في الخطوات المذكورة أعلاه ، بحيث يمكن العثور عليه. لذلك ، يتم تحديد خاصية earlySingletonExposure أن تكون صحيحة مع الظروف الأخرى ، وتتم إضافة العملية التالية addSingletonFactory . هنا مصنع كائن يتوافق مع Beanname (A). يتم تحقيق تنفيذ طريقة getObject الخاصة بها من خلال طريقة getEarlyBeanReference . أولاً ، دعونا نلقي نظرة على تنفيذ AddSingleTonfactory
void المحمي AddSingleTonfactory (سلسلة beanname ، ObjectFactory <؟> singletonfactory) {Assert.notnull (singletonfactory ، "يجب ألا يكون مصنع Singleton NULL") ؛ synchronized (this.singletonobjects) {if (! this.singletonobjects.containskey (beanname)) {this.singletonfactory.put (beanname ، singletonfactory) ؛ this.earlysingletonobjects.remove (beanname) ؛ this.registeredSingletons.Add (Beanname) ؛ }}} تخزين البيانات إلى ذاكرة التخزين المؤقت من المستوى الثالث ، وقم بتطهير بيانات ذاكرة التخزين المؤقت من المستوى الثاني بناءً على Beanname. هناك نقطة مهمة للغاية هنا ، وهي ضبط القيمة في ذاكرة التخزين المؤقت من المستوى الثالث ، والتي هي النقطة الأساسية لمعالجة الربيع للتبعيات الدائرية. طريقة getEarlyBeanReference هي تنفيذ getObject. يمكن اعتباره ببساطة أنه يرجع مثيل كائن مليء بـ A. بعد تعيين ذاكرة التخزين المؤقت من المستوى 3 ، تبدأ عملية ملء خصائص الكائن A. الوصف التالي لا يحتوي على مطالبات رمز المصدر ، مجرد مقدمة موجزة.
عند ملء A ، وجدت أن هناك حاجة إلى حبة من النوع B ، لذلك واصلت استدعاء طريقة getBean لإنشائها. عملية الذاكرة هي نفسها بالضبط كما هو مذكور أعلاه. ثم ذهبت إلى عملية ملء الفاصوليا من النوع C. نفس المكالمة getBean (C) للتنفيذ. عند ملء عقار A ، اتصلت بـ GetBean (A). دعنا نستمر من هنا إلى أن أدعو Object sharedInstance = getSingleton(beanName), نفس الرمز ، لكن منطق المعالجة مختلف تمامًا.
كائن محمي getSingleton (سلسلة beanname ، boolean allearyrelyReference) {object singletOnObject = this.singletonobjects.get (beanname) ؛ if (singletOnObject == null && issingletoncurrallyincreation (beanname)) {synchronized (this.singletonObjects) {singletonobject = this.earlysingletonobjects.get (beanname) ؛ if (singletOnObject == null && allearyreference) {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) ؛ } ومع ذلك ، لا يمكن الحصول على الكائن من singletonobjects. نظرًا لأن A موجود في مجموعة singletonsCurrentlyInCreation ، فإنه يدخل المنطق التالي ، ويأخذه من مستويات Cache earlySingletonObjects ، ولكن لم يتم العثور عليه. ثم يجد مصنع الكائن المقابل من ذاكرة التخزين singletonFactories استدعاء طريقة getObject للحصول على كائن المثيل الخاص بـ A الذي لم يتم ملؤه بالكامل ، ثم يحذف بيانات ذاكرة التخزين المؤقت من المستوى الثالث ، ويملأ بيانات ذاكرة التخزين المؤقت من المستوى الثاني ، ويعتمد هذا الكائن A. C على ملء مثيل A ، على الرغم من أن هذا A غير مكتمل. بغض النظر عن إكمال ملء الطراز C ، يمكنك وضع C في Cache singletonObjects من المستوى الأول وتنظيف بيانات ذاكرة التخزين المؤقت من المستوى الثاني والثالث في نفس الوقت. في نفس العملية ، إذا تم ملء C على B ، يتم ملء B. وبالمثل ، إذا تم ملء B على A ، يتم ملء A. هذه هي الطريقة التي يحل الربيع المراجع الدائرية.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.