[Spring] Detailed explanation of three-level cache to solve circular dependencies

What is circular dependency

The process of registering a bean object:
Spring scans the class to get the BeanDefinition - generates the bean based on the obtained BeanDefinition - now infers the construction method based on the class - uses reflection to get an object based on the inferred construction method - fills in the attributes in the initial object (dependency injection ) – If a method of the original object is AOPed, then a proxy object must be generated based on the original object – Put the final generated proxy object into the singleton pool (singletonObjects, also called the first-level cache), and next time you getBea Just take it directly from the singleton pool

Circular dependencies are injected into each other during dependency injection, such as

public class AService{
    
    
	@Autowired
	private BService bService;
}
public class BService{
    
    
	@Autowired
	private AService aService;
}

Level 3 caching process

Spring uses the third-level cache strategy to solve the circular dependency problem. The process is roughly as follows.
Create the bean of AService:
AServicecreated
Because there is no BService yet, create a BService.
BService created
During the creation process, because AService has already appeared in the third-level cache, it will be The following operations
Fill AService in BService
: Because the attributes of BService have been assigned, the initialization of BService is over and can be directly placed in the first-level cache. The complete process is: At
BService instantiation process
this time, BService has been instantiated, and then the dependencies in AService can be injected. :
AService instantiation part 2
The complete flow chart is as follows:
The completion flow chart of three-level cache to resolve circular dependencies

Simple source code analysis

First, doCreateBean in the AbstractAutowireCapabaleBeanFactory class (I found it using ctrl+shift+alt+n)
first creates a bean original object, and there is no dependency injection at this time.

		BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
    
    
            instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
        }

        if (instanceWrapper == null) {
    
    
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
        
        Object bean = instanceWrapper.getWrappedInstance();

Then put the lambda expression into the third level cache

        if (earlySingletonExposure) {
    
    
            if (this.logger.isTraceEnabled()) {
    
    
                this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
            }
			//放入三级缓存,这个lambda表达式是为了执行aop生成代理对象用的,如果有aop操作,就会拿到代理对象出来
            this.addSingletonFactory(beanName, () -> {
    
    
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }

Next is the dependency filling of A

	this.populateBean(beanName, mbd, instanceWrapper);

In this, you will come to a getSingleton method, which is to find BService in the cache.

	//allowEarlyReference是是否允许循环依赖
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    
    
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
    
    
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
    
    
                synchronized(this.singletonObjects) {
    
    
                	//一级缓存中找
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
    
    
                    	//二级缓存中找
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
    
    
                        	//三级缓存中找
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
    
    	//找到了
                            	//这里相当于上面图文分析中BService在三级缓存中找到AService
                            	//直接用lambda表达式注册,然后把他移动到二级缓存中
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

But obviously AService will definitely not be found, and then it will go to createBean again, create a BService, and go to the above-mentioned getSingleton like A. At this time, A will be found in the third-level cache, and then injected

After the filling is completed, BService will be placed in the first-level cache, B in the third-level cache will be removed, and then it will end.

	exposedObject = this.initializeBean(beanName, exposedObject, mbd);

After the creation of the entire BService is completed, the above dependency filling of A will end, and then A will also execute exposedObject = this.initializeBean(beanName, exposedObject, mbd); this line of code, A will also end.

It is easier to understand the code by combining it with graphic demonstrations

Guess you like

Origin blog.csdn.net/qq_67548292/article/details/131943024