Spring advanced source notes: Comprehensive analysis of Spring IoC cyclic dependency problem with code implementation!

1. What is circular dependency

Circular dependency is actually a circular reference, that is, two or more Beans hold each other to form a closed loop. For example, A depends on B, B depends on C, and C depends on A.

Note that this is not a cyclic call of a function, but the interdependence of objects. The loop call is actually an endless loop, unless there is a final condition.

The circular dependency scenarios in Spring include:

  • Cyclic dependency of constructor (constructor injection)
  • Circular dependency of Field property (set injection)

Among them, the cycle of dependence constructor method to solve the problem, only to throw BeanCurrentlyInCreationExceptionan exception, the object is a method of exposure in advance in solving the property cycle dependent, spring used.

2. Circular dependency processing mechanism

  • Cyclic dependency of singleton bean constructor parameters (cannot be resolved)
  • prototype prototype bean cyclic dependency (cannot be resolved)

Regardless of whether it is through the constructor parameter circular dependency or the circular dependency generated by the setXxx method during the initialization of the prototype bean , Spring will report an error directly.

AbstractBeanFactory.doGetBean() method :

if (isPrototypeCurrentlyInCreation(beanName)) {
    
    
	throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
    
    
	Object curVal = this.prototypesCurrentlyInCreation.get();
	return (curVal != null &&
		(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}

Before getting the bean, if the prototype bean is being created, an exception will be thrown directly. The prototype bean will be marked before it beanNameis created, it is being created, and the mark will be deleted after the creation is complete

try {
    
    
	//创建原型bean之前添加标记
	beforePrototypeCreation(beanName);
	//创建原型bean
	prototypeInstance = createBean(beanName, mbd, args);
}
finally {
    
    
	//创建原型bean之后删除标记
	afterPrototypeCreation(beanName);
}

Summary: Spring does not support circular dependencies of prototype beans .

  • Singleton bean passes setXxxor @Autowiredperforms circular dependencies

The theoretical basis of Spring's circular dependency is based on Java's reference transfer. When obtaining a reference to an object, the properties of the object can be set later, but the constructor must be before the reference is obtained

Spring uses setXxxor **@Autowired method to solve the circular dependency is actually done by exposing an ObjectFactoryobject in advance . Simply put, after ClassA calls the constructor to complete the object initialization, it passes the object instantiated by ClassA before calling the setClassB method of ClassA. ObjectFactoryExpose to the Spring container** in advance .

  • Spring container initialization ClassA is exposed to the Spring container in advance after initializing the object through the constructor.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
    
    
		if (logger.isDebugEnabled()) {
    
    
			logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
		}
		//将初始化后的对象提前已ObjectFactory对象注入到容器中
 		addSingletonFactory(beanName, new ObjectFactory<Object>() {
    
    
 		@Override
 		public Object getObject() throws BeansException {
    
    
 			return getEarlyBeanReference(beanName, mbd, bean);
 		}
 	});
 }
  • ClassA calls the setClassB method. Spring first tries to obtain ClassB from the container. At this time, ClassB does not exist in the Spring container.
  • The Spring container initializes ClassB and also exposes ClassB to the Spring container in advance
  • ClassB calls the setClassA method, and Spring obtains ClassA from the container, because ClassA has been exposed in the first step, so the ClassA instance can be obtained
    • ClassA obtains ClassB through the spring container and completes the object initialization operation.
  • In this way, both ClassA and ClassB have completed the object initialization operation, solving the circular dependency problem.

This article refers to "Spring Advanced Source Notes", students who need to add assistant VX: C18173184271get it for free

If you need this full version 《Spring高级源码笔记》, you only need to support me in this article.

A lot of support, you can get information for free-after three consecutive years (promise: 100% free)

Quick start channel: add assistant VX: C18173184271get it for free! Full of sincerity! ! !

Spring interview feature article click here! ! !

Guess you like

Origin blog.csdn.net/Java_Caiyo/article/details/113061360