Der Frühling hat eine eigene Lösung für kreisförmige Abhängigkeiten zwischen Bohnen. Der Schlüsselpunkt ist Level Three Cache. Diese Lösung kann natürlich nicht alle Probleme lösen, sondern kann nur die kreisförmige Abhängigkeit von Nichtkonstruktoren im Bohnen-Singleton-Modus lösen.
Wir werden von der Initialisierungsreihenfolge von A-> B-> ca beginnen, was bedeutet, dass in der Bohne von A Fälle von B benötigt werden, Fälle von C in der Bohne von B benötigt werden, Fälle von A in der Bohne von C benötigt werden, und Fälle von A sind in der Bohne von C. Natürlich ist diese Notwendigkeit keine Abhängigkeit wie ein Konstruktor. Sobald die Voraussetzungen verfügbar sind, können wir beginnen. Es besteht kein Zweifel, dass wir eine erste initialisieren werden. Die Initialisierungsmethode lautet org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
Protected <T> T detgetbean (endgültiger String -Name, endgültige Klasse <T> fordert type, endgültiges Objekt [] args, boolesche typecheckOnly) löscht Beansexception (endgültige String beanname = transformedBeanname (Name)); Objektbohne; // Überprüfen Sie den Singleton -Cache für manuell registrierte Singletons eifrig. Objekt SharedInstance = Getsingleton (Beanname); // Focus 1 if (SharedInstance! } else {logger.debug ("zurückgegebene Instanz von Singleton Bean '" + BeAnName + "'"); }} bean = getObjectforBeanInstance (SharedInstance, Name, Beanname, NULL); } else {// scheitern, wenn wir diese Bean -Instanz bereits erstellen: // Wir werden in einer kreisförmigen Referenz angenommen. if (isPrototypecurentIncreation (Beanname)) {werfen neuer beancrealeincreationException (Beanname); } // Überprüfen Sie, ob in dieser Fabrik eine Bean -Definition vorliegt. Beanfactory parentBeanFactory = getParentbeanFactory (); if (parentBeanFactory! String nametolookup = originalBeanname (Name); if (args! = null) {// Delegation an Eltern mit expliziten Argumenten. return (t) parentBeanFactory.getbean (nametolookup, args); } else {// no args -> delegieren Sie die Standard -GetBean -Methode. return parentBeanFactory.getBean (nametolookup, forders type); }} if (! typecheckonly) {markbeanAscreated (Beanname); } try {endgültige rootbeandefinition mbd = getMergedLocalbeanDeFinition (Beanname); checkmergedbeandefinition (MBD, Beanname, Args); // Garantie der Initialisierung von Bohnen, von denen die aktuelle Bohne abhängt. String [] Develementson = mbd.getDependson (); if (abhängigSon! } RegisterDependentBean (abhängigSonbean, Beanname); getBean (abhängigSonbean); }} // Bean -Instanz erstellen. if (mbd.issingleton ()) {// beunruhigt 2 SharedInstance = Getsingleton (Beanname, New ObjectFactory <Object> () {@Override public Object getObject () wirft Beansexception {try {return createBean (Beanname, mbd, argsxcs). wurden durch den Erstellungsprozess eingestellt, um eine kreisförmige Referenz zu ermöglichen. Bean = GetObjectForBeanInstance (SharedInstance, Name, Beanname, MBD); } else if (mbd.isprototype ()) {// Es ist ein Prototyp -> Erstellen Sie eine neue Instanz. Objektprototypeinstanz = null; Versuchen Sie {vorprototypecreation (Beanname); prototypeinstance = createBean (Beanname, mbd, args); } endlich {AfterPrototypecreation (Beanname); } bean = getObjectforBeanInstance (Prototypeinstanz, Name, Beanname, MBD); } else {String scopename = mbd.getScope (); Final Scope Scope = this.scopes.get (Scopename); if (scope == null) {neue illegaleStateException werfen ("Kein Bereich für den Scope -Namen '" + Scopename + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); Bean = GetObjectForBeanInstance (ScopedInstance, Name, Beanname, MBD); } catch (illegalStateException ex) {werfen neue BeancreationException (Beanname, "Scope" " + Scopename +" 'nicht für den aktuellen Thread aktiv; Betrachten Sie " +", um einen Scoped -Proxy für diese Bohne zu definieren, wenn Sie sich von einem Singleton darauf beziehen ", Ex); }}} catch (Beansexception ex) {CleanUpAfterBeanCreationFailure (Beanname); Ex werfen; }} // Überprüfen Sie, ob der erforderliche Typ mit dem Typ der tatsächlichen Bean -Instanz übereinstimmt. if (fordersType! = null && bean! } catch (typemismatchException ex) {if (logger.isdebugenabled ()) {logger.debug ("" Bean " + name +" 'in den erforderlichen Typ [" + clasutils.getqualifiedName (forders type) +"] ", ex); } neue BeannotofRequiredTypexception (Name, forders fordertype, bean.getClass ()); }} return (t) bean; } Diese Methode ist sehr lang, lassen Sie uns nach und nach darüber sprechen. Schauen wir uns zuerst unseren Fokus an. Object sharedInstance = getSingleton(beanName ) erhält ein Singleton -Objekt aus der Sammlung von Singletons basierend auf dem Namen. Schauen wir uns diese Methode an, und es ist endlich org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
Protected Object Getsingleton (String beanname, boolean erlaubtearterferenz) {Object SingletonObject = this.singletonObjects.get (Beanname); if (SingletonObject == NULL && issingLetoncurentIncreation (Beanname)) {synchronized (this.singletonObjects) {SingletonObject = this.earlysingLetonObjects.get (Beanname); if (SingletonObject == null && duldearLeferference) {ObjectFactory <?> SingletonFactory = this.singletonFactory.get (Beanname); if (SingletonFactory! = null) {SingletonObject = SingletonFactory.getObject (); this. this.singletonfactory.remove (Beanname); }}} return (SingletonObject! = null_object? SingletonObject: null); } Jeder muss auf diese Methode achten, es ist sehr wichtig. Wir haben den Cache Level 3 zu Beginn erwähnt, und einer der Gebrauchspunkte ist hier. Welcher Cache Level 3 ist das? singletonObjects des ersten Level -Cache werden mit instanziierten SingletonObjects platziert. Die zweite Stufe earlySingletonObjects von Singleton -Objekten, die im Voraus ausgesetzt sind (nicht vollständig zusammengebaut). Die SingletonFactores der dritten Stufe speichern die Objektfabrik des zu instanziellen Objekts. Schauen wir uns die Logik an. Das erste Mal, dass ich in this.singletonObjects.get(beanName) Anschließend bestimmt isSingletonCurrentlyInCreation , ob die Daten im sekundären Cache erhalten werden können.
public boolean issingletoncurentincreation (String beanname) {return this.singletOnscrentincreation.contains (Beanname); } Wird der Beanname in das singletonsCurrentlyInCreation -Set aufgenommen, enthält der eingehende Beanname? Es gibt keinen Platz, um es vorher einzustellen, daher schließt es es definitiv nicht ein. Daher gibt diese Methode false zurück, und der nachfolgende Prozess wird nicht übrig bleiben. Die getSingleton -Methode gibt null zurück.
Schauen wir uns den Fokus an 2. Es ist auch ein getSingleton , aber es ist der wahre Prozess, eine Bohne zu erstellen. Wir können sehen, dass ein anonymer ObjectFactory -Objekt übergeben wird. Die GetObject -Methode namens CreateBean, die eigentliche Methode zum Erstellen einer Bean. Natürlich können wir es beiseite legen und weiterhin unsere getSingleton -Methode betrachten
öffentliches Objekt Getsingleton (String Beanname, ObjectFactory <?> SingletonFactory) {assert.notnull (Beanname, "Beanname 'darf nicht null sein"); synchronisiert (this.singletonObjects) {Object SingletonObject = this.singletonObjects.get (BeAnName); if (SingletonObject == NULL) {if (this.singletonScourent -Intruction) {neue BeancreationNotallowedException werfen (BeAnName "," Singleton Bean Creation, die nicht zulässig sind, während die Singletons dieser Fabrik in einer Zerstörung " +" sind (keine Bean von einer Beanfaktorik in einer Zerstörungsmethode implementieren!) "). } if (logger.isdebugenabled ()) {logger.debug ("Erstellen einer gemeinsamen Instanz von Singleton Bean" " + BeAnName +" '"); } Beersingletoncreation (Beanname); boolean t Newsingleton = false; boolean RecordsuppressedExceptions = (this.SuppresSheedExceptions == null); if (recordsuppressedExceptions) {this.suppressedexceptions = new LinkedHashSet <Uneces> (); } try {SingletonObject = SingletonFactory.getObject (); Newsingleton = True; } catch (illegalStateException ex) {// hat das Singleton -Objekt implizit in der Zwischenzeit angezeigt -> // Wenn ja, gehen Sie damit fort, da die Ausnahme diesen Zustand anzeigt. SingletonObject = this.singletonObjects.get (Beanname); if (SingletonObject == null) {throw ex; }} catch (BeancreationException ex) {if (recordsuppressedExceptions) {für (Ausnahme unterdrückteException: this.suppressedExceptions) {ex.AddrelatedCause (SuppressedException); }} throw ex; } endlich {if (recordsuppressedexceptions) {this.suppresedExceptions = null; } AfterSingletoncreation (Beanname); } if (Newsingleton) {addSingleton (Beanname, SingletonObject); }} return (SingletonObject! = null_object? SingletonObject: null); }} Der erste Satz dieser Methode Object singletonObject = this.singletonObjects.get(beanName) Die beforeSingletonCreation -Methode wird dann aufgerufen.
Protected Void Beersingletoncreation (String beanname) {if (! this.increationCheckClusions.Contains (BeAnName) &&! thissingletonScrentincreation. }} Unter ihnen ist der Prozess des Hinzufügens von Beanname zum singletonsCurrentlyInCreation -Set. Dieser Satz ist sehr wichtig und wird später verwendet. Rufen Sie dann die GetObject -Methode von SingletonFactory an, um den realen Erstellungsprozess durchzuführen. Schauen wir uns den oben genannten realen Erstellungsprozess an createBean Die Kernlogik darin ist doCreateBean .
Protected Object Docreatebean (endgültiger String -Beanname, endgültiger Rootbeandefinition MBD, endgültiges Objekt [] args) {// Die Bean instanziiert. BeanWrapper InstanceWrapper = null; if (mbd.issingleton ()) {InstanceWrapper = this.factoryBeanInstanceCache.remove (Beanname); } if (instanceWrapper == null) {InstanceWrapper = createBeanInstance (Beanname, mbd, args); } Final Object bean = (InstanceWrapper! Class <?> BeanType = (InstanceWrapper! // Erlauben Sie Postprozessoren, die fusionierte Bean-Definition zu ändern. synchronisiert (mbd.postprocessinglock) {if (! mbd.postprocessed = true; }} // Sachgemäß Singletons, um kreisförmige Referenzen aufzulösen // selbst wenn sie durch Lebenszyklus -Schnittstellen wie beanfactoryAware ausgelöst werden. // beunruhigt3 boolean frühsingletonexposure = (mbd.issingleton () && this.allowcircularReferences && issingletoncurrentIncreation (Beanname)); if (frühsingtletOnexposure) {if (logger.isdebugenabled ()) {logger.debug ("eifrig zwischengespeicherte Bean" + Beanname + "', um die Auflösung potenzieller zirkulärer Referenzen zu ermöglichen"); } addSingletonFactory (Beanname, New ObjectFactory <Object> () {@Override öffentliches Objekt getObject () löst Beansexception aus {return getearlyBeanReference (Beanname, Mbd, Bean);}}); } // Initialisieren Sie die Bean -Instanz. Objekt exposedObject = bean; try {populateBean (Beanname, mbd, InstanceWrapper); if (exposedObject! = null) {exposedObject = initializeBean (Beanname, exponsedObject, mbd); }} catch (throwable ex) {if (ex instanceof beancreationException && beanname.equals (((beancreationException) ex) .getBeanname ())) {throw (beancreationException) ex; } else {throune BeancreationException (mbd.getResourcedescription (), Beanname, "Initialisierung von Bean fehlgeschlagen", ex); }} if (frühsingtletOnexposition) {Objekt frühsingletonReference = Getsingleton (Beanname, false); if (frühesingletonReference! } else if (! this.allowrawinjectionDepiteWrapping && Hasdependentbean (Beanname)) {String [] abhängigbeans = getDependentBeans (Beanname); Set <String> tatsächliche DependentBeans = new LinkedHashSet <String> (abhängigbeans.length); für (String -abhängigeBean: abhängigeBeans) {if (! EntfernungLetonifcreatedForyPeCheckOnly (abhängigeBean)) {trupleDependentBeans.add (abhängigeBean); }} if (! trupleDependentbeans.isempty ()) {Neue BeancrentincreationException (Beanname, "Bean mit Namen '" + BeAnName + "' wurde in andere Beans injiziert [" + StringUtils.CollectionTocommadelimited String (tatsächliche Dependent). bedeutet, dass andere Bohnen die endgültige Version der " +" -Bohne nicht verwenden. }}}}} // Die Bean als verfügbar registrieren. probieren {registerDisposableBeanifnegary (Beanname, Bean, MBD); } catch (BeanDefinitionValidationException ex) {neue BeancreationException (mbd.getResourcedescription (), Beanname, "Ungültige Zerstörungssignatur", Ex); } return exposedObject; } createBeanInstance erstellt ein Objekt mit Reflexion. Werfen wir einen Blick auf den Bewertungspunkt 3 earlySingletonExposure -Attributwert. Einer der Urteilspunkte isSingletonCurrentlyInCreation(beanName)
public boolean issingletoncurentincreation (String beanname) {return this.singletOnscrentincreation.contains (Beanname); } Ich stellte fest, dass das skreationsübergreifende SingletOn -Set verwendet wird. Der Beanname wurde in den obigen Schritten ausgefüllt, sodass er gefunden werden kann. Daher wird festgestellt, dass die earlySingletonExposure -Eigenschaft in Kombination mit anderen Bedingungen wahr ist, und der folgende Prozess wird addSingletonFactory hinzugefügt. Hier ist eine Objektfabrik, die dem Beannamen (a) entspricht. Die Implementierung seiner GETObject -Methode wird durch getEarlyBeanReference -Methode erreicht. Schauen wir uns zunächst die Implementierung von AddSingletonFactory an
Protected Void addSingletonFactory (String beanname, ObjectFactory <?> SingletonFactory) {Assert.notnull (SingletonFactory, "Singleton Factory daged nicht null"); synchronisiert (this.singletonObjects) {if (! This.singletonObjects this. this.registeredsingletons.add (Beanname); }}} Speichern von Daten auf den Cache SingletonFactores der dritten Ebene, löschen Sie die Cache -Daten der zweiten Ebene basierend auf Beanname. Hier gibt es einen sehr wichtigen Punkt, bei dem der Wert in den Cache der dritten Ebene eingestellt wird, was der Kernpunkt der Verarbeitung von kreisförmigen Abhängigkeiten durch die Frühling ist. Die getEarlyBeanReference -Methode ist eine Implementierung von GETObject. Es kann einfach berücksichtigt werden, dass es eine Objektinstanz zurückgibt, die mit A gefüllt ist. Nach der Einstellung des Cache der Stufe 3 beginnt das Füllen der Eigenschaften des A -Objekts. Die folgende Beschreibung enthält keine Quellcode -Eingabeaufforderungen, nur eine kurze Einführung.
Beim Füllen von A stellte ich fest, dass eine Bohne vom Typ B benötigt wird, sodass ich die GetBean -Methode weiter aufgerufen habe, um sie zu erstellen. Der Speichervorgang ist genau der gleiche wie oben. Dann ging ich zum Prozess des Füllens einer Typ -C -Bohne. Der gleiche Anruf getBean (c) zum Ausführen. Beim Füllen einer Eigenschaft A rief ich GetBean (a) an. Lassen Sie uns von hier aus fortfahren, dass ich Object sharedInstance = getSingleton(beanName), demselben Code, genannt habe, aber die Verarbeitungslogik ist völlig anders.
Protected Object Getsingleton (String beanname, boolean erlaubtearterferenz) {Object SingletonObject = this.singletonObjects.get (Beanname); if (SingletonObject == NULL && issingLetoncurentIncreation (Beanname)) {synchronized (this.singletonObjects) {SingletonObject = this.earlysingLetonObjects.get (Beanname); if (SingletonObject == null && duldearLeferference) {ObjectFactory <?> SingletonFactory = this.singletonFactory.get (Beanname); if (SingletonFactory! = null) {SingletonObject = SingletonFactory.getObject (); this. this.singletonfactory.remove (Beanname); }}} return (SingletonObject! = null_object? SingletonObject: null); } Dennoch wird das Objekt von SingletonObjects erhalten, die nicht erhalten werden können. Da sich A im Set in singletonsCurrentlyInCreation befindet, tritt er in die folgende Logik ein und nimmt ihn aus dem zweiten Cache in earlySingletonObjects aus zweiter Stufe, wurde aber immer noch nicht gefunden. Dann findet er die entsprechende Objektfabrik aus dem Cache singletonFactories Rufen Sie getObject -Methode auf, um das Instanzobjekt von A zu erhalten, das nicht vollständig gefüllt wurde, und löscht dann die Cache-Daten auf der dritten Ebene, füllt die Cache-Daten der zweiten Ebene und gibt dieses Objekt zurück. Unabhängig davon, wie Füllung im C-Stil abgeschlossen ist, können Sie C in den Cache singletonObjects der ersten Ebene einstellen und gleichzeitig die Daten der Caches der zweiten und dritten Stufe reinigen. Im gleichen Prozess ist B gefüllt, wenn C von B gefüllt ist. In ähnlicher Weise ist A gefüllt, wenn B von A gefüllt ist. So löst Frühling kreisförmige Referenzen.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.