Springサイクル依存の3つの方法(おすすめ)


引用:循環依存とはN種類の中で循環ネスト参照であり、日常的な開発においてnewオブジェクトの方式でこのような循環依存が発生すると、プログラムは実行時にメモリオーバーフローエラーが発生するまで循環的に起動します。次にspringはサイクル依存を解決すればいいです。
第一種類:コンストラクタパラメータの循環依存性
Spring容器は、作成中のBean識別子の各々を「現在作成されたBeanプール」に配置し、Bean識別子は作成中ずっと保持されます。
この池では、ビーンを作成する過程で、自分がすでに「現在ビーンプールを作成している」と発見した場合は投げます。
BenCurrenntlyInCreationException異常はサイクル依存を表します。作成したビーンに対しては「現在作成されているビーンプール」からクリアされます。
まず、私たちは最初に三つのビーンを初期化します。

public class StudentA { 
 
  private StudentB studentB ; 
 
  public void setStudentB(StudentB studentB) { 
    this.studentB = studentB; 
  } 
 
  public StudentA() { 
  } 
   
  public StudentA(StudentB studentB) { 
    this.studentB = studentB; 
  } 
}

public class StudentB { 
 
  private StudentC studentC ; 
 
  public void setStudentC(StudentC studentC) { 
    this.studentC = studentC; 
  } 
   
  public StudentB() { 
  } 
 
  public StudentB(StudentC studentC) { 
    this.studentC = studentC; 
  } 
}

public class StudentC { 
 
  private StudentA studentA ; 
 
  public void setStudentA(StudentA studentA) { 
    this.studentA = studentA; 
  } 
 
  public StudentC() { 
  } 
  
  public StudentC(StudentA studentA) { 
    this.studentA = studentA; 
  } 
}
はい、上記は基本的な3つのクラスです。StudentA有参構造はStudentBです。StudentBの有参構造はStudentCであり、StudentCの有参構造はStudentAであり、これにより循環依存が生じる場合、
私たちはこの三つのBeanをSpringに管理して、有参構造の実用化を使っています。

<bean id="a" class="com.zfx.student.StudentA"> 
  <constructor-arg index="0" ref="b"></constructor-arg> 
</bean> 
<bean id="b" class="com.zfx.student.StudentB"> 
  <constructor-arg index="0" ref="c"></constructor-arg> 
</bean> 
<bean id="c" class="com.zfx.student.StudentC"> 
  <constructor-arg index="0" ref="a"></constructor-arg> 
</bean>
次はテストクラスです。

public class Test { 
   public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml"); 
     //System.out.println(context.getBean("a", StudentA.class)); 
   } 
 }
  実行結果エラーメッセージは以下の通りです。
Caused by:org.springframe ebook.beans.factory.BenCurrenntly InCreationException:  
    Errar creating bean with name'a':Requested bean is currently in creation:Is there an unrerererelavable circuular reference? 
最初の文を理解すれば、このエラーは驚くべきではないです。Spring容器はまず一例StudentAを作成し、StudentAはStudentBに依存して、その後Aを「現在Bean池を作成します」に置いて、StudentBを作成し、Student BはStudentCに依存して、Bを「直前にBenプールを作成します」に配置します。この時、StudentCを作成します。この時Studentはすでに池の中にいますので、エラーが発生します。プールの中のBeanは初期化されていないので、エラーに依存します。
第二種類:setter方式の単例、標準方式
setter方式で注入するなら、まずSpring中のBeanの実像を見たほうがいいです。
 
図中の前の2つのステップで分かったように、Springは、まずBeanオブジェクトを実装してからオブジェクト属性を設定します。
設定ファイルをセットにして注入します。

<!--scope="singleton"(        ) --> 
<bean id="a" class="com.zfx.student.StudentA" scope="singleton"> 
  <property name="studentB" ref="b"></property> 
</bean> 
<bean id="b" class="com.zfx.student.StudentB" scope="singleton"> 
  <property name="studentC" ref="c"></property> 
</bean> 
<bean id="c" class="com.zfx.student.StudentC" scope="singleton"> 
  <property name="studentA" ref="a"></property> 
</bean>
次はテストクラスです。

 public class Test { 
   public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml"); 
     System.out.println(context.getBean("a", StudentA.class)); 
   } 
 } 
印刷結果は:
comp.zfx.student.StudentA@1fbfd6 
なぜset方式で間違えないですか?
上記の図に合わせて、Springは最初に構造的な実用化されたBeanオブジェクトであり、Springはこの実用化されたオブジェクトを一つのMapに置いて、Springはこの設定されていない属性の実用化されたオブジェクト参照を取得する方法を提供しています。   私達の例として、StudentA、StudentB、StudentCがSpringによって具体化された後、続いてオブジェクトの属性が設定されます。StudentAはStudentBに依存します。Mapから中にある一つの例StudentBオブジェクトを取り出します。これを類推して、ループの問題が出ません。
次はSpringソースの実現方法です。以下のソースコードはSpringのBeanカバンの中のDefaultSingleton BenRegistry.Java類の中にあります。

/** Cache of singleton objects: bean name --> bean instance(          Map  ) */ 
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); 
   
  /** Cache of singleton factories: bean name --> ObjectFactory(     Bean    ) */ 
  private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16); 
   
  /** Cache of early singleton objects: bean name --> bean instance(           ) */ 
  private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); 
   
  /** Set of registered singletons, containing the bean names in registration order(            ) */ 
  private final Set<String> registeredSingletons = new LinkedHashSet<String>(64); 
  /** 
   *        
   *           
   * Add the given singleton factory for building the specified singleton 
   * if necessary. 
   * <p>To be called for eager registration of singletons, e.g. to be able to 
   * resolve circular references. 
   * @param beanName the name of the bean 
   * @param singletonFactory the factory for the singleton object 
   */ 
  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.singletonFactories.put(beanName, singletonFactory); 
        this.earlySingletonObjects.remove(beanName); 
        this.registeredSingletons.add(beanName); 
      } 
    } 
  }
第三種類:setter方式の原型、prototype
設定ファイルを変更すると:

<bean id="a" class="com.zfx.student.StudentA" <span style="color:#FF0000;">scope="prototype"</span>> 
    <property name="studentB" ref="b"></property> 
  </bean> 
  <bean id="b" class="com.zfx.student.StudentB" <span style="color:#FF0000;">scope="prototype"</span>> 
    <property name="studentC" ref="c"></property> 
  </bean> 
  <bean id="c" class="com.zfx.student.StudentC" <span style="color:#FF0000;">scope="prototype"</span>> 
    <property name="studentA" ref="a"></property> 
  </bean>
scope=「prototype」は要求毎にインスタンスオブジェクトを作成するという意味です。両者の違いは、状態のあるbeanはProttypeスコープを使用し、無状態のものはsingleton単例スコープを使用することです。
テストケース:

public class Test { 
  public static void main(String[] args) { 
    ApplicationContext context = new ClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml"); 
    <strong>//       Spring     ,    scope="prototype"                 </strong> 
    System.out.println(context.getBean("a", StudentA.class)); 
  } 
}
印刷結果:
Caused by:org.spring frame ebook.beans.factory.BenCurrenntlyInCreationException:Errar creating bean with name'a':Requested bean is currently in creation:Is there an unrelable circurle?
なぜ原型のパターンが間違って報告されましたか?
「prototype」の作用領域Beanに対して、Spring容器は依存注入を完了できません。「prototype」の作用領域のBean,Spring容量です。
アクチュエータはキャッシュを行わないので、作成中のBeanを前倒しで露出することはできません。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。