1。序文
スプリングは負荷がかかる可能性があること、つまり、実際に使用されているときに豆をインスタンス化することができることを知っています。もちろん、そうではありません。たとえば、Beanの怠zyinitプロパティを構成すると、春の荷重時間を制御できます。現在、マシンのパフォーマンス、メモリなどは比較的高く、基本的には怠zyなロードを使用しません。 Beanはコンテナの開始時にロードされ、スタートアップ時間はもう少し長くなります。このようにして、ビジネスの使用のために実際にBeanが取得されると、多くの負担を減らすことができます。これは後で分析されます。豆を使用するとき、最も直接的な方法は、豆を積み込む源であるFactroyからそれらを取得することです。
最近、私はプロジェクトに取り組む際に奇妙な問題に遭遇しました。つまり、Bean依存噴射の精度はBean直接注入の順序に関連していますが、通常の状況では順序とは何の関係もありません。あなたが急いでいるなら、私にあなたに一つ一つあなたに話させてください。
2。注入順序に関連する通常の豆循環依存関係
2.1円形の依存関係の例と原則
パブリッククラスbeana {private beanb beanb; public beanb getbeanb(){return beanb;} public void setbeanb(beanb beanb){this.beanb = beanb;}}}パブリッククラスbeanb {private beana beana; public beana getbeana(){return beana;} public void setbeana(beana beana){this.beana = beana;}}}<bean id = "beana"> <プロパティ名= "beanb"> <ref bean = "beanb"/> </property> </bean>
<bean id = "beanb"> <プロパティ名= "beana"> <ref bean = "beana"/> </property> </bean>
上記の円形の依存関係注入は、春が早期の摂取機能を提供するため、正常に機能します。まず、春にSingletonobjectsという名前の同時マップがあり、すべてのインスタンス化および初期化された豆を保存しますが、SingletonFactoriesは、解決する必要があるBean情報(BeanNameおよびCallback Factory)を保存するために使用されます。インスタンス化するとき、 getBean(“beanA”);まず、SingletonObjectsにBeanaがあるかどうかを確認してください。
(1)
Object sharedInstance = getsingleton(beanname); // getsingleton(beanname、true); if(sharedInstance!= null && args == null){if(logger.isdebugenabled()){if(issingledoncurrentyincreation(beanname)){eagheded ea gred.debug(de debug(de debug(de debug) Bean '" + beanName +"'それはまだ完全に初期化されていません - 円形参照の結果 "); } else {logger.debug( "singleton beanのキャッシュされたインスタンスを返す '" + beanname + "'"); }} //それが通常のBeanの場合、それはsharedInstance.getObject(); bean = getObjectforBeanInstance(sharedInstance、name、beanname、null);}を返します;}保護されたオブジェクトGetSingleton(String beanName、boolean approwearlyreference){object singletonobject = this.singletonobjects.get(beanname); if(singletonobject == null){synchronized(this.singletonobjects){singletonobject = this.eallysingletonobjects.get(beanname); if(singletonobject == null && approwearlyreference){objectory singletonfactory =(objectFactory)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);}最初は間違いなくBeanaがないので、 allowCircularReferences=trueが設定されている場合(デフォルトがTrue)、現在のBeanはシングルピースであり、Beanは現在作成されています。
(2)
Boolean EarlySingletoneXposure =(Mbd.issingleton()&& this.AllowCircularReferences && IssingleToncurlentyincreation(beanname));
if(EartySingletOneXposure){if(logger.isdebugenabled()){ogger.debug( "eatelyly caching bean '" + beanname + "'潜在的な円形参照を解決できる");} addingletletonfactory(beanname、new objectory(){public getobject() getearlybeanReference(beanname、mbd、bean);};} protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactory.put(beanName, SingletonFactory); this.eallysingletonobjects.remove(beanname); this.registeredsingletons.add(beanname); }}}次に、BeanBをインスタンス属性に注入します。属性を注入すると、 getBean(“beanB”) singletonobjectsに含まれていないことを発見すると、beanbをインスタンス化し、シングルトンファクターを入れてからビーナを注入してから、 getBean(“beanA”);この時点で、Getsingletonはインスタンス化されたBeanaを返します。 Beanbが初期化されたら、BeanbをSingletonObjectsに追加してから戻し、Beanaが初期化され、BeanaをSingletonObjectsに追加してから戻ります
2.2ループ依存関係を可能にするスイッチ
public class testcircle2 {private final final static classpathxmlapplicationcontext moduleContext; private static test test; static {moduleContext = new ClassPathXMLApplicationContext(new String [] {"beans-circile.xml"}); moduleContext.setAllowCircularReferences(false); test =(test)moduleContext.getBean( "test");} public static void main(string [] args){system.out.println(test.name);}}}}ClassPathxMLApplicationContextクラスには、循環依存関係がデフォルトで真であることが許可されているかどうかを制御するプロパティを許可するプロパティがあります。それをfalseに設定した後、円形の依存関係は依然として正常に実行できることがわかります。ソースコードを見てください:
public classpathxmlapplicationContext(String [] configlocations)throws BeanSexception {this(configlocations、true、null);} public classpathxmlapplicationContext(string [] configlocations、boolean refresh、applicationcontext parent)throws beansexception {super(parent); setconfiglocations(configlocations); if(refresh){refresh();}}} public classpathxmlapplicationContext(string [] configlocations、boolean refresh、applicationcontext parent)throws beansexception {super(parent); setconfiglocations(configlocations); if(refresh){refresh();}}} classpathxmlapplicationContextがデフォルトで構築されると、コンテナが更新されることを知ってください。
更新方法は、refrespeanFactoryを呼び出します:
Protected final void refreshbeanfactory()throws beansexception {if(hasbeanfactory()){destroybeans(); CloseBeanFactory();} try {// Bean Factory DefaultListableBeanFactory beanFactory = createBeanFactory(); // Bean FactoryプロパティのカスタマイズBeanFactory(BeanFactory); LoadBeanDefinitions(BeanFactory);同期(this.beanfactorymonitor){this.beanfactory = beanfactory; }} catch(IOException ex){show new ApplicationContextException( "I/OアプリケーションコンテキストのXMLドキュメントの解析[" + getDisplayName() + "]、ex);}}} Protected void CustomizeBeanFactory(DefaultListableBeanFactory BeanFactory){if(this.allowbeandefinitionOverriding!= null){beanFactory.setAllowBeanDiontionOverriding(this.AllowBeanDefinitionOverriding.boolAnvalue();} beanfactory.setallowcircularreferences(this.allowcircularreferences.booleanvalue();}}}}ここでは、 moduleContext.setAllowCircularReferences(false)を呼び出す前に、春ごとに左にカスタマイズビーンファクトリーが実行されたことがわかります。最後の理由は、設定を呼び出す前に、Bean Factoryが更新されているため、テストコードが次のように変更されていることです。
public class testcircle {private final final static classpathxmlapplicationcontext modulecontext; private static test test; static {//コンテナコンテキストを初期化しますが、コンテナmodulecontext = new classpathxmlapplicationcontext(new String [] {"beans-circile.xml"}、false); moduleContext.setAllowCircularReferences(false); //コンテナmodulecontext.refresh()を更新します。 test =(test)moduleContext.getBean( "test");} public static void main(string [] args){system.out.println(test.name);}}}}これで、テストが例外をスローします。
原因:org.springframework.beans.factory.beancreationexception:クラスパスリソース[Beans-circile.xml]で定義された名前「beana」でbeanの作成エラー[Beans-circile.xml]:Beanプロパティ「Beanb」を設定しながらBean 'Beanb'への参照を解決できません。ネストされた例外はorg.springframework.beans.factory.beancreationexception:クラスパスリソースで定義された名前「beanb」でbeanを作成するエラー[beans-circile.xml]:Beanプロパティ「Beana」を設定しながらBean 'Beana'への参照を解決できません。ネストされた例外はorg.springframework.beans.factory.beancurllingtingincreationexception: 'beana'という名前でBeanの作成エラーです:要求されたBeanは現在作成中です:未解決の円形の参照はありますか?
3。工場豆と普通の豆サイクリック依存関係 - 注入順に関連する
3.1テストコード
工場の豆
Public Class MyFactoryBeanはFactoryBeanを実装し、InitialBean {private string name; private test test; public string getname(){return name;} public void setname(string name){this.name = name;} public depententbean getDepentBean(){return depententbean;} public void setdepentbean DependentBean;} private DependentBean DependentBean; public Object getObject()throws {return test;} public class getObjectType(){// todo auto-feenated method stub returt test.class;} public boolean issingleton(){// todo auto-venated method rurtionet system.out.println( "name:" + this.name); test = new test(); test.name = depententbean.dosomething() + this.name;}}簡単にするために、パブリック変数を書くだけです
パブリッククラステスト{public string name;} public class depententbean {public string dosomething(){return "hello:";}@autowiredPrivateテストテスト;} XML構成
<bean id = "test"> <Property name = "deplowentbean"> <bean> </bean> </property> <property name = "name" value = "zlx"> </property> </bean>
Factory Bean MyFactoryBean関数は、テストクラスをラップすることです。まず、MyFactoryBeanのプロパティを設定し、次にMyFactoryBeanのAfthPropertiessetメソッドでテストインスタンスを作成し、プロパティを設定します。 MyFactoryBeanをインスタンス化すると、最終的にGetObjectメソッドを呼び出して作成されたテストオブジェクトを返します。ここで私のfefactorybeanはdepentbeanに依存しており、依存者自体はテストに依存しているため、これは循環依存関係です
テスト:
public class testcircle2 {private final final static classpathxmlapplicationcontext moduleContext; private static test test; static {moduleContext = new ClassPathXMLApplicationContext(new String [] {"beans-circile.xml"}); test =(test)moduleContext.getBean( "test");} public static void main(string [] args){system.out.println(test.name);}}}}結果:
原因:org.springframework.beans.factory.beancreationexception:com.alibaba.test.circle.dependentbean#1c701a27 'という名前のbeanの作成エラーネストされた例外はorg.springframework.beans.factory.beancreationexception:autowire field:private com.alibaba.test.circle.test com.alibaba.test.circle.dependentbean.test;ネストされた例外はorg.springframework.beans.factory.beancurllingtingincreationexception:name 'test'を持つBeanの作成エラーです:getobjectから現在作成中のFactorybean
3.2理由の分析
インスタンス化されたテストの場合getBean(“test”)がトリガーされ、現在の豆が存在するかどうかがわかります
存在しない場合は、テストのインスタンスを作成します。作成後、現在のBean情報はSingletonFactoriesシングルピースマップに配置されます。
次に、属性依存者をインスタンスに注入します。属性インジェクションを使用すると、 getBean(“depentBean”)が使用されます。
依存者が存在しないことがわかった場合は、依存者をインスタンス化してからsingletonfactoriesに入れます。
次に、自動噴射噴射テスト、そしてgetBean(“test”);この時点で(1)Getsingletonはインスタンス化されたテストを返します。テストはファクトリービーンであるため、return test.getObject();
MyFactoryBeanのAfterPropertiessetはまだ呼ばれていないため、 test.getObject() nullを返します。
以下は、次の春の豆の作成プロセスです。
getBean() - > create instance-> autowired-> set property-> afthpropertiesset
つまり、GetObjectメソッドを呼び出すことは、AfterPropertiessetメソッドよりも早く呼び出されました。
次に、MyFactoryBeanを次のように変更しましょう。
public object getObject()スロー例外{// todo auto-fenated method stubif(null == test){avhdpropertiesset();} return test;} public void afterpropertiesset()スロー例外{if(null == test){system.out.println( "name:" + this.name); test = new test(); test.name = depententbean.dosomething() + this.name;}}つまり、最初にgetobject内で判断する場合は、 test==null次に、AfterPropertiEssetを呼び出してから、 test==nullがAfterPropertiesset内でテストインスタンスを作成している場合、見た目が良くなり、本当に問題を解決したいと思います。しかし、実際には、Afterpropertiessetは内部的にdependentBeanを使用し、この時点でdepentBean=null使用するため、まだ機能していません。
3.3それを解決する方法について考えています
3.2分析の理由は、MyFactoryBeanが最初に作成され、MyFactoryBeanの作成プロセス中にDepentbeanが作成されたことです。 Depentbeanを作成するとき、自動化されたMyFactoryBeanのインスタンスが必要です。次に、getobjectメソッドがafterpropertiessetを呼び出す前に呼び出されるため、nullが返されます。
最初にdepentbeanを作成してからmyfactorybeanを作成した場合は?次の分析が行われます。
まず、Depentbeanがインスタンス化され、SingletonFactoriesに追加されます
Depentbeanインスタンスは自動化されたテストであるため、テストインスタンスが最初に作成されます。
テストインスタンスを作成してから、SingletonFactoriesに参加します
テストインスタンスは、属性にdepentbeanインスタンスを挿入するため、 getBean(“depentBean”);
getBean(“depentBean”) SingletonFactoriesに依存症がすでにあることを発見し、依存症のオブジェクトを返します
depententbeanは工場の豆ではないため、依存者を直接返します
テストインスタンスはdepentbeanインスタンスに正常に注入されます。テストインスタンス初期化OK
Depentbeanインスタンス自動化されたテストインスタンスOK
この分析によると、最初にdepentbeanを作成し、次にmyFactorybeanをインスタンス化することが可能です。 XMLを次のように変更します。
<bean id = "dependentbean"> </bean> <bean id = "test"> <property name = "deplowentbean"> <ref bean = "depententbean"/> </jeppertion> <property name = "name" value = "zlx"> </property> </bean>
テスト実行結果:
名前:ZLX
こんにちは:ZLX
本当に問題ない場合は、この分析によれば、上記のXML構成が調整されている場合、テストは依存症よりも早く作成されたため、間違いなくエラーが発生します。これはテスト後に当てはまります。さらに、工場の豆が工場の豆に依存している場合、宣言の順序に関係なく必然的に失敗することを想像できます。
3.3考え
上記の最初に、MyFactoryBeanで使用する必要がある依存者を注入し、次にMyFactoryBeanを注入し、問題が解決します。では、別の豆にID = "テスト"で作成されたオブジェクトを使用する必要がある場合、この豆をどのように注入する必要がありますか?
同様の方法で成功しますか?誰もが考えるためにそれを残してください^^
public class usetest {@autowiredprivateテストテスト;}<bean id = "usetest"> </bean> <bean id = "depententbean"> </bean> <bean id = "test"> <property name = "depropentbean"> <ref bean = "depententbean"/> </joppety> <プロパティ名= "name" value = "zlx"> </bean> </bean> </bean> </bean> <
4。概要
普通の豆が相互依存している場合、豆の注射の順序は関係ありませんが、工場豆と普通の豆が相互依存する場合、通常の豆を最初にインスタンス化する必要があります。これは、工場の豆の特殊性のためです。つまり、GetObjectメソッドを備えています。
さて、上記はこの記事のコンテンツ全体です。この記事の内容には、すべての人の研究や仕事に特定の参照値があることを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。 wulin.comへのご支援ありがとうございます。