Springには、豆間の円形依存関係に対する独自のソリューションがあります。重要なポイントは、レベル3キャッシュです。もちろん、このソリューションはすべての問題を解決することはできず、Bean Singletonモードの非構築者の円形依存性のみを解くことができます。
a-> b-> caの初期化順序から開始します。つまり、bのインスタンスがaの豆に必要であり、cの豆でcのインスタンスが必要であり、aのインスタンスがcの豆に必要であり、aの豆では必要です。もちろん、このニーズはコンストラクターのような依存関係ではありません。前提条件が利用可能になったら、開始できます。最初に初期化することは間違いありません。初期化方法はorg.springframework.beans.factory.support.AbstractBeanFactory#doGetBeanです
保護された<t> t dogetbean(最終文字列名、最終クラス<t> rebulictype、final objects [] args、boolean typecheckonly)throws beansexception {final string beanname = transformedbeanname(name);オブジェクトビーン; //手動で登録されたシングルトンのシングルトンキャッシュを熱心に確認します。 Object sharedInstance = getSingleton(beanname); //フォーカス1 if(sharedInstance!= null && args == null){if(elbger.isdebugenabled()){if(sissingletoncurlentionincreation(beanname)){logger.debug( " 参照"); } else {logger.debug( "singleton beanのキャッシュされたインスタンスを返す '" + beanname + "'"); }} bean = getobjectforbeaninstance(sharedInstance、name、beanname、null); } else {//このbeanインスタンスをすでに作成している場合は失敗します://円形の参照内で想定されます。 if(isprotopecurlynelyincreation(beanname)){beancurlentyincreationexception(beanname); } //この工場に豆の定義が存在するかどうかを確認します。 BeanFactory ParentBeanFactory = getParentBeanFactory(); if(parentbeanfactory!= null &&!containsbeandefinition(beanname)){//見つかりません - >親をチェックします。 string nametolookup = originalbeanname(name); if(args!= null){//明示的なargsを持つ親への委任。 return(t)parentbeanfactory.getBean(nametolookup、args); } else {// argsなし - >標準のgetbeanメソッドに委任します。 return parentbeanfactory.getBean(nametolookup、rebyttype); }} if(!typecheckonly){markbeanascreated(beanname); } try {final rootbeandefinition mbd = getMergedLocalBeanDefinition(beanName); CheckMergedBeanDefinition(MBD、BeanName、Args); //現在の豆が依存している豆の初期化を保証します。 string [] Dependson = mbd.getDependson(); if(depenentson!= null){for(String Dependsonbean:Dependson){if(isdependent(beanname、Dependsonbean)){Throw new BeanCreationException(MBD.GetResourcedESCription()、BeanName、「 ' + Beanname + "' '" + Depensonbean + ""); } RegisterDependentBean(expententsOnbean、beanName); getBean(依存者); }} // Beanインスタンスを作成します。 if(mbd.issingleton()){// cberce 2 sharedinstance = getsingleton(beanname、new objectFactory <object>(){@override public object getobject()try {return createbean(beanname、mbd、args);} catch(beansexception ex) //は、豆の一時的な参照を受け取った豆を除去するために、作成プロセスによって実施されます。 bean = getobjectforbeaninstance(sharedinstance、name、beanname、mbd); } else if(mbd.isprototype()){//プロトタイプ - >新しいインスタンスを作成します。オブジェクトprototypeinstance = null; try {beforeprototypeCreation(beanname); prototypeinstance = createbean(beanname、mbd、args); }最後に{afthprototypecreation(beanname); } bean = getobjectforbeaninstance(prototypeinstance、name、beanname、mbd); } else {string scopename = mbd.getScope();最終スコープスコープ= this.scopes.get(scopename); if(scope == null){新しいIllegalStateException( "スコープ名に登録されているスコープなし '" + scopename + "'"); } try {object scopedInstance = scope.get(beanname、new objectFactory <object>(){@Override public object getobject()throws beansexception {beforeprototypecreation(beanname); try {return createbean(beanname、mbd、args); bean = getobjectforbeaninstance(scopedinstance、name、beanname、mbd); } catch(IllegalStateException ex){新しいbeancreationException(beanname、 "scope '" + scopename + "'は現在のスレッドではアクティブではありません。シングルトンから参照する場合は、この豆のスコーププロキシを定義する「 +」を検討してください。 }}} catch(beansexception ex){cleanupafterbeancreationfailure(beanname); Exを投げる; }} //必要なタイプの場合は、実際のBeanインスタンスのタイプと一致します。 if(requiredtype!= null && bean!= null &&!rebytytype.isassignablefrom(bean.getclass())){try {return gettypeconverter()。 } catch(typemismatchException ex){if(logger.isdebugenabled()){ogger.debug( "bean '" + name + "'に必要なタイプに[" + classutils.getQualifiedName(rebyniedtype) + "]"、ex); }新しいbeannotOfRequiredTypeexception(name、requiredType、bean.getClass())を投げる; }} return(t)bean; }この方法は非常に長いです。少しずつ話しましょう。最初に私たちの焦点を見てみましょう。 Object sharedInstance = getSingleton(beanName )名前に基づいて、シングルトンのコレクションからシングルトンオブジェクトを取得します。この方法を見てみましょう。ついにorg.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)です。
保護されたオブジェクトGetSingleton(String beanName、boolean approwearlyreference){object singletonobject = this.singletonobjects.get(beanname); if(singletonobject == null && singretoncurlentyincreation(beanname)){synchronized(this.singletonobjects){singletonobject = this.eylysingletonobjects.get(beanname); if(singletonobject == null && approwearlyreference){objectFactory <?> singletonfactory = this.singletonfactory.get(beanname); if(singletonfactory!= null){singletonobject = singletonfactory.getObject(); this.ylylysingletonobjects.put(beanname、singletonobject); this.singletonfactory.remove(beanname); }}} return(singletonobject!= null_object?singletonobject:null); }誰もがこの方法に注意を払わなければなりません、それは非常に重要です。最初にレベル3キャッシュについて言及しましたが、使用点の1つはここにあります。どのレベル3キャッシュですか?最初のレベルキャッシュのsingletonObjectsインスタンス化されたSingletonObjectsで配置されます。第2レベルのearlySingletonObjects 、事前に露出している(完全に組み立てられていない)Singletonオブジェクトを保存します。第3レベルのSingletonFactoriesには、オブジェクトのオブジェクトファクトリーがインスタンス化されます。レベル3キャッシュを説明した後、ロジックを見てみましょう。初めてthis.singletonObjects.get(beanName)に来たときは、nullを返します。次に、 isSingletonCurrentlyInCreation 、データをセカンダリキャッシュで取得できるかどうかを決定します。
public boolean issingletoncurlentyincreation(string beanname){return this.singletonscurllyningincreation.contains(beanname); } BeanNameはsingletonsCurrentlyInCreationセットに含まれていますか?以前に設定する場所はないので、間違いなくそれを含めません。したがって、この方法はfalseを返し、その後のプロセスは残されません。 getSingletonメソッドはnullを返します。
Focus 2を見てみましょうgetSingletonでもありますが、Beanを作成する本当のプロセスです。匿名のオブジェクトファクターオブジェクトが渡されていることがわかります。Beanを作成する実際の方法であるCreateBeanと呼ばれるGetObjectメソッド。もちろん、私たちはそれを脇に置いて、 getSingletonメソッドを見続けることができます
パブリックオブジェクトGetSingleton(String BeanName、ObjectFactory <?> SingletonFactory){assert.notnull(beanname、 "'beanname' be null");同期(this.singletonobjects){object singletonobject = this.singletonobjects.get(beanname); if(singletonobject == null){if(this.singletonscurllinge -struction){show new beancreationnotallowedexception(beanname、 "singleton beanの作成は許可されていません。 } if(logger.isdebugenabled()){logger.debug( "Singleton Beanの共有インスタンスの作成 '" + beanname + "'"); } beforesingletoncreation(beanname); Boolean Newsingleton = false; boolean recordsuppredressexceptions =(this.suppredressexceptions == null); if(RecordSuppredessExceptions){this.suppressexceptions = new linkedhashset <例外>(); } try {singletonobject = singletonfactory.getObject(); Newsingleton = true; } catch(IllegalStateException ex){//シングルトンオブジェクトはその間に暗黙的に表示されました - > //はいの場合、例外はその状態を示しているため、それを進めます。 singletonobject = this.singletonobjects.get(beanname); if(singletonobject == null){show ex; }} catch(beancreationException ex){if(recordsuppredessexceptions){for(exception suptressexception:this.suppredessexceptions){ex.addrelated -cause(suptressexception); }} exを投げる; }最後に{if(recordsuppredestexceptions){this.suppredessexceptions = null; } aftersingletoncreation(beanname); } if(newsingleton){addsingleton(beanname、singletonobject); }} return(singletonobject!= null_object?singletonobject:null); }}このメソッドの最初の文はObject singletonObject = this.singletonObjects.get(beanName)最初のレベルのキャッシュから取得します。これは間違いなくnullです。次に、 beforeSingletonCreationメソッドが呼び出されます。
保護されたボイドbeforesingletoncreation(string beanname){if(!this.increationcheckexclusions.contains(beanname)&&!thisingletonscurrentyincreation.add(beanname)){新しいbeancurrentyincreationexception(beanname); }}その中には、 singletonsCurrentlyInCreationセットにbeannameを追加するプロセスがあります。このセットは非常に重要であり、後で使用されます。次に、SingletonFactoryのGetObjectメソッドに電話して、実際の作成プロセスを実行します。上記の実際の作成プロセスを見てみましょうcreateBean内部のコアロジックはdoCreateBeanです。
保護されたオブジェクトDocreateBean(最終的な文字列beanName、最終的なrootbeandefinition MBD、final Object [] args){// Beanをインスタンス化します。 BeanWrapper InstanceWrapper = null; if(mbd.issingleton()){instancewrapper = this.factorybeaninstancache.remove(beanname); } if(instancewrapper == null){instancewrapper = createbeanInstance(beanname、mbd、args); } final object bean =(instancewrapper!= null?instancewrapper.getWrappingInstance():null); class <? //ポストプロセッサがマージされた豆の定義を変更できるようにします。同期(mbd.postprocessinglock){if(!mbd.postprocessed){applymergedbeandefinitionPostprocessors(MBD、BeanType、BeanName); mbd.postprocessed = true; }} // cacheシングルトンは、cache cache cache cach beanfactoryawareのようなライフサイクルインターフェイスによってトリガーされた場合でも、循環参照を解決できます。 // cbersing3 boolean areimsingletonexposure =(mbd.issingleton()&& this.allowcircularReferences && singingletoncurlentyincreation(beanname)); if(earlysingletonexposure){if(logger.isdebugenabled()){ogger.debug( "eatelyly cached bean '" + beanname + "'潜在的な円形参照を解決することを可能にする"); } addsingletonFactory(beanName、new objectFactory <object>(){@Override public object getObject()throws beansexception {return getearlybeanReference(beanname、mbd、bean);}}); } // Beanインスタンスを初期化します。オブジェクトExposedObject = Bean; try {populatebean(beanname、mbd、instancewrapper); if(exposedObject!= null){exposedObject = InitializeBean(beanName、exposedObject、MBD); }} catch(throwable ex){if(ex instance of beancreationexception && beanname.equals(((beancreationexception)ex).getbeanname())){thro(beancreationexception)ex; } else {throw beancreationException(mbd.getResourcedescription()、beanName、 "Bean Failed"、ex); }} if(areysingletonexposure){object ertysingletonreference = getsingleton(beanname、false); if(earlysingletonReference!= null){if(exposedObject == bean){exposedObject = earlysingletonReference; } else if(!this.allowrawinjectiondespitewrapping && hasdependentbean(beanname)){string [] depententbeans = getDependentBeans(beanName); Set <string>実際のdependentBeans = new LinkedHashset <String>(DependentBeans.Length); for(String DependentBean:DependentBeans){if(!RemoseSingLeTonifCreatedFutyPecheckonly(depententBean)){actualldependentbeans.add(depententbean); }} if(!actualdependentbeans.isempty()){新しいbeancurlentyincreationexception(beanname with name '" + beanname +"'が他の豆に注入されました[" + stringutils.collectiontocommadelimitedstring(futial be secular) +" + " +" + " +" + collectiontocommadelimitedstring)つまり、他の豆は「 +」の最終バージョンを使用しないという意味です。これは、多くの場合、「aloweAgerinit」フラグをオフにして「 +」 'getBeanNamesOfType」を使用することを検討します。 }}}}} // beanを使い捨てとして登録します。 try {RegisterDisposableBeanifnedexerary(beanName、Bean、MBD); } catch(beandefinitionValidationException ex){新しいbeancreationexception(mbd.getResourcedescription()、beanName、 "invalid destruction Signature"、ex); } exposedObjectを返します。 } createBeanInstance 、反射を使用してオブジェクトを作成します。 Judging Point 3 earlySingletonExposure属性値を見てみましょう。判決の1つはisSingletonCurrentlyInCreation(beanName)ポイントします
public boolean issingletoncurlentyincreation(string beanname){return this.singletonscurllyningincreation.contains(beanname); } Singletonscurlentyincreationセットが使用されていることがわかりました。 BeanNameは上記の手順で記入されているため、見つけることができます。したがって、 earlySingletonExposureプロパティは、他の条件と組み合わせて真であると判断され、 addSingletonFactory次のプロセスが追加されます。これは、BeanName(a)に対応するオブジェクトファクトリです。 GetObjectメソッドの実装は、 getEarlyBeanReferenceメソッドを通じて達成されます。まず、AddSingleTonFactoryの実装を見てみましょう
保護されたvoid addsingletonfactory(string beanname、objectactory <?同期(this.singletonobjects){if(!this.singletonobjects.containskey(beanname)){this.singletonfactory.put(beanname、singletonfactory); this.eallysingletonobjects.remove(beanname); this.registeredsingletons.add(beanname); }}}データを第3レベルのキャッシュシングルトンファクトリーに保存し、BeanNameに基づいて2番目のレベルのキャッシュデータをクリアします。ここには非常に重要なポイントがあります。これは、値をサードレベルのキャッシュに設定することです。これは、スプリングの円形依存関係の処理の中心点です。 getEarlyBeanReferenceメソッドは、getobjectの実装です。 Aで満たされたオブジェクトインスタンスを返すと考えることができます。レベル3キャッシュを設定した後、Aオブジェクトのプロパティを埋めるプロセスが開始されます。次の説明には、ソースコードプロンプトがなく、簡単な紹介です。
Aを埋めるとき、私はタイプB豆が必要であることがわかったので、それを作成するためにGetBeanメソッドを呼び出し続けました。メモリプロセスは上記とまったく同じです。その後、私はタイプCビーンを埋めるプロセスに行き、同じコールGetBean(C)が実行されるように呼び出されます。プロパティaを埋めるとき、私はgetbean(a)に電話しました。ここからObject sharedInstance = getSingleton(beanName),呼んでいますが、処理ロジックは完全に異なります。
保護されたオブジェクトGetSingleton(String beanName、boolean approwearlyreference){object singletonobject = this.singletonobjects.get(beanname); if(singletonobject == null && singretoncurlentyincreation(beanname)){synchronized(this.singletonobjects){singletonobject = this.eylysingletonobjects.get(beanname); if(singletonobject == null && approwearlyreference){objectFactory <?> singletonfactory = this.singletonfactory.get(beanname); if(singletonfactory!= null){singletonobject = singletonfactory.getObject(); this.ylylysingletonobjects.put(beanname、singletonobject); this.singletonfactory.remove(beanname); }}} return(singletonobject!= null_object?singletonobject:null); }それでも、オブジェクトはSingletonObjectsから取得できません。 aはsingletonsCurrentlyInCreationセットにあるため、彼は次のロジックに入り、第2レベルのキャッシュearlySingletonObjectsからそれを取得しますが、それでもまだ発見されていません。その後、彼は第3レベルのキャッシュsingletonFactories getObjectメソッドを呼び出して、完全に満たされていないAのインスタンスオブジェクトを取得し、3レベルのキャッシュデータを削除し、2番目のレベルのキャッシュデータを埋め、このオブジェクトAを返します。 Cスタイルの詰め物がどのように完了しても、第1レベルのキャッシュsingletonObjectsにCを入れて、同時に第2レベルと3番目のレベルのキャッシュのデータをクリーニングできます。同じプロセスでは、CがBに依存している場合、Bが満たされます。同様に、BがAに依存している場合、Aは満たされます。これは、Springが円形の参照を解決する方法です。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。