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:
Because there is no BService yet, create a BService.
During the creation process, because AService has already appeared in the third-level cache, it will be The following operations
: 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
this time, BService has been instantiated, and then the dependencies in AService can be injected. :
The complete flow chart is as follows:
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