Springが循環依存関係を解決する方法:createBeanInstance-> addSingletonFactory-
> getSingleton
-
Springの3レベルキャッシュ
singletonObjects:シングルトンプールは、ライフサイクル
全体を早期に通過したBeanを格納しますSingletonObjects:事前に公開されたBeanキャッシュは、インスタンス化を完了したBeanまたはaop
singletonFactoriesのプロキシオブジェクトを格納します:キャッシュはObjectFactoryです、および値が格納されている関数、wrapIfNecessaryウォークを実行し、AOPロジックが必要かどうかを確認し、earlySingletonObjectsキャッシュに配置すると、キャッシュによってこの要素が削除されます。 -
Springに関連する3レベルのキャッシュを見ると、開発者がキャッシュを使用して循環依存の問題を解決する方法を理解できます。主に2つの場所で、1つはライフサイクルのインスタンス化段階であり、もう1つはライフサイクルです。初期化後のAOPのステージ。
-
次の例:
@Component
Class A {
@Autowired
private B b;
}
Class B {
@Autowired
private A a;
}
- 開始doCreateBean
if (instanceWrapper == null) {
// 走生命周期中的实例化 返回类型为BeanWrapper getWrappedInstance方法就会返回该bean的实例化的bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 之后进三级缓存
// 三个条件 单例,allowCircularReferences=true,A正在创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 添加到三级缓存 vale传入了一个函数 getEarlyBeanReference中wrapIfNecessary走AOP
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
- Bの注入を開始するには、最初にdoGetBeanのgetSingletonメソッドに移動しますが、キャッシュにBのBeanが見つかりません。
次に、BのdoCreateBeanメソッドを開始します。Bはインスタンス、プロパティインジェクション、AにインジェクトされたときのdoGetBeanの次のメソッドを開始します。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 先从单例池找 如果找不到 并且发现要找的这个bean正在创建中...
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 二级缓存找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 从三级缓存 取数据 getObject 执行之前lambda表达式函数 添加到二级缓存 三级缓存remove该元素
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
-
このようにして、Aのインスタンス(元のオブジェクト)またはAのAOPインスタンス(プロキシオブジェクト)を取得し、インジェクションを実行してクラスBのBeanのライフサイクル全体を完了することができます。また、クラスAは次のインジェクションを完了することもできます。 B。
-
wrapIfNecessaryメソッドは、クラスAOPプロキシが完了したかどうかを判別します。プロキシが事前に完了している場合、プロキシは再度プロキシされないため、注入および生成されたBeanがオブジェクトであることが保証されます。
-
Springの循環依存関係を要約
すると、特別なポストプロセッサーを持たないリターンBean(単純なBeanとaops)のみを解決できます。ポストプロセッサで新しいクラスを直接返す場合、ここで問題が発生します。allowCircularReferences= falseを変更して、循環依存関係を自分で制御できます。