序文
Springの循環依存は実際には非常に単純なものです。インタビュー中によく聞かれます。一般的に、インタビュアーはSpringの循環依存の問題を解決する方法、またはクラスAの属性がBを指しているかどうかを尋ねます。クラスBの属性Springでこの問題を解決する方法を示します。ねえ、これが本当にそれを解決する方法の観点から始められれば、それは本当に穴に落ちるでしょう。彼らは皆、それをどのように解決するかを尋ねていましたが、あなたにそれを解決させるとは言いませんでした。彼らは皆、それが春であると言いました。そしてもちろん、問題はSpringがそれをどのように解決するかです!循環依存関係がどのように生成されるか、Springがそれをどのように解決するか、プラスポイント、そしてなぜ3レベルのキャッシュが必要なのかを説明するだけです。これらのSpring循環依存関係を取得することに何の問題もありません!
循環依存とは何ですか?
まず、Springには2種類の循環依存関係があります。1つはコンストラクターの循環依存関係であり、もう1つは属性の循環依存関係です。これらの2種類の依存関係は、実際には循環参照です。つまり、2つ以上のBeanが相互に保持し、最終的に閉ループを形成します。これが
ほぼ意味です。上記のコードは、コンストラクターサイクルの依存関係と属性サイクルの依存関係を詳細に説明しています。
コンストラクターの依存関係
@Service
public class A {
@Autowired
private B b;
public A(B b){
this.b = b;
}
public void f(){
b.f();
}
}
@Service
public class B {
@Autowired
private A a;
public B(A a){
this.a = a;
}
public void f(){
System.out.println("BBBBBBBBB中的f方法");
}
}
@ComponentScan(value = "com.tao.spring")
public class TestMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestMain.class);
applicationContext.getBean(A.class).f();
}
}
運転結果
二月 21, 2021 10:13:18 下午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'a' defined in file [G:\GitLab\spring5\target\classes\com\tao\spring\A.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'b' defined in file [G:\GitLab\spring5\target\classes\com\tao\spring\B.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'a' defined in file [G:\GitLab\spring5\target\classes\com\tao\spring\A.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'b' defined in file [G:\GitLab\spring5\target\classes\com\tao\spring\B.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1325)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1171)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$8/362239120.getObject(Unknown Source)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:849)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:88)
at com.tao.spring.TestMain.main(TestMain.java:19)
属性の循環依存
@Service
public class A {
@Autowired
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public void f(){
b.f();
}
}
@Service
public class B {
@Autowired
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public void f(){
System.out.println("BBBBBBBBB中的f方法");
}
}
@ComponentScan(value = "com.tao.spring")
public class TestMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestMain.class);
applicationContext.getBean(A.class).f();
}
}
実行結果
Springは、構築サイクル依存関係と属性依存関係を処理するときに2つの異なる実行結果を持ちます。これは、Springが構築サイクル依存関係の問題を解決できないためです。BeanCurrentlyInCreationException
この例外をスローすることしかできず、構築のエラー結果に表示されます。サイクル操作。この例外は、属性の循環依存関係を処理する際にSpringで処理できます。これは、Springがオブジェクトを事前に公開する方法を使用しているためです。これは、一般に次のように知られています。三级缓存
Springは循環依存をどのように解決しますか?
答えはすでに上にあります!これが3レベルのキャッシュです。したがって、3レベルのキャッシュが属性の循環依存の問題を具体的に解決する前に、まず知識を予約しましょう。
前提知識:
Springでオブジェクトを作成するときは、最初にインスタンス化->属性を入力->初期化することを知っています。Springの
作成プロセスの後、2つの循環依存関係を確認できます。最初のタイプの構造循環依存関係はインスタンス化中に発生します。フェーズ、ここで構築メソッドを呼び出す必要があるため、2番目の属性循環依存関係は、属性の入力で発生します。これは、属性割り当て操作の完了です。
3レベルキャッシュ
これらの3レベルキャッシュは、DefaultSingletonBeanRegistryクラスのsingletonObjects、earlySingletonObjects、およびsingletonFactoriesを参照します。
- singletonObjects:シングルトンオブジェクトのキャッシュ
- EarlySingletonObjects:事前に公開されたシングルトンオブジェクトのキャッシュ
- singletonFactories:シングルトンオブジェクトファクトリのキャッシュ
Beanを作成するときに最初に頭に浮かぶのは、キャッシュからシングルトンBeanを取得することです。このキャッシュはsingletonObjectsです。使用できず、オブジェクトが作成されている場合は、第2レベルのキャッシュearlySingletonObjectsから取得されます。それでも使用できず、getObject()を介してsingletonFactoriesを取得できる場合は、第3レベルのキャッシュsingletonFactory.getObject()(第3レベルのキャッシュ)から取得されます。取得された場合は、singletonFactoriesから削除されます。 EarlySingletonObjectsに配置されます。実際、これは第3レベルのキャッシュから第2レベルのキャッシュに移動されます。
上記の3レベルのキャッシュの分析から、循環依存関係を解決するためのSpringのトリックは、3レベルのキャッシュであるsingletonFactoriesにあることがわかります。このキャッシュのタイプはObjectFactoryです。循環依存関係を解決するための鍵は次のとおり
发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用
です。
3レベルのキャッシュが必要なのはなぜですか
第1レベルのキャッシュのみが循環依存関係を解決できる場合、
まず、ここに格納されているオブジェクトは、半製品、完成品、半製品(インスタンス化のみが完了し、初期化は完了していません)であることがわかります。完成品(つまり、インスタンス化が完了し、初期化が完了した場合)、完成品が第1レベルのキャッシュに入れられた場合(第1レベルのキャッシュはオブジェクトの取得を容易にするために使用されます)、マルチスレッド環境では、システムは第1レベルのキャッシュからデータを取得し、半製品を取得することが可能です。属性はnullになります
第2レベルのキャッシュのみが循環依存関係を解決できる場合、第2レベルのキャッシュを使用する
と、第1レベルのキャッシュに完成品を格納でき、第2レベルのキャッシュに半完成品を格納できます。この場合、2次キャッシュで十分です。2次キャッシュは循環依存の問題を解決できます。
第3レベルのキャッシュの重要性
通常のクラスを作成する場合、第2レベルのキャッシュは完全に管理可能ですが、作成されたクラスがプロキシクラスの場合、問題が発生します。