Circular Dependency-Talking about Spring Circle Reference

How Spring solves circular dependencies: createBeanInstance --> addSingletonFactory
-->getSingleton

  1. Spring three-level cache
    singletonObjects: the singleton pool stores the beans that have passed the complete life cycle
    earlySingletonObjects: the bean cache exposed in advance stores the beans that have completed the instantiation or the proxy object of the aop
    singletonFactories: the cache is an ObjectFactory, and the value is stored A function, take the wrapIfNecessary walk, whether the AOP logic is required, put it in the earlySingletonObjects cache and the cache remove this element

  2. Looking at the three-level cache involved in Spring, we can understand how developers use cache to solve the problem of circular dependencies, mainly in two places, one is the instantiation stage in the life cycle, and the other is the life cycle. The stage of AOP after initialization .

  3. Next example:

@Component
Class A {
    
    
	@Autowired
	private B b;
}

Class B {
    
    
	@Autowired
	private A a;
}
  1. A start 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));
}
  1. To start injecting B, first go to the getSingleton method in doGetBean, and no B’s bean is found in the cache.
    Then start the doCreateBean method of B, B starts the instance, property injection, the following method of doGetBean when injected into A
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;
}
  1. In this way, you can get an instance of A (original object) or AOP instance (proxy object) of A, and perform injection to complete the full life cycle of the bean of class B, and class A can also complete the injection of B.

  2. The wrapIfNecessary method will determine whether the class AOP proxy is completed. If the proxy is completed in advance, it will not proxy again, ensuring that the injected and generated beans are an object.

  3. Summarizing
    Spring's circular dependencies, it can only solve return beans (simple beans and aops) that do not have a special post processor. If you directly return a new class in the post processor, there will be a problem here. You can modify allowCircularReferences=false to control the circular dependency yourself.

Guess you like

Origin blog.csdn.net/weixin_45657738/article/details/109643311