Explanation of Spring's circular reference source code

Next, let's fully analyze the circular reference of Spring today

What is circular reference? I don't need to force it. Go directly to the code and debug and analyze the source code in the whole process

@Configuration
@ComponentScan({"com.carry"})
public class Appconfig {
}
@Component
public class X {

	@Autowired
	private Y y;

	public X() {
		System.out.println("x Construction method of");
	}
}
@Component
public class Y {
	
	@Autowired
	private X x;

	public Y() {
		System.out.println("y Construction method of");
	}
}


Let's first remember these two concepts - spring bean (hereinafter referred to as bean) and object;
1. Spring beans - objects managed by the spring container may have gone through the full spring bean life cycle (why is it possible? Are there any beans that have not gone through the bean life cycle? The answer is yes, we will analyze the details later), and finally exist in the spring container; A bean must be an object
2. Object -- any object instantiated according to java syntax rules, but an object is not necessarily a spring bean

OK, let's get to the point. Let's start with doGetBean and look at the doGetBean method

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		//First, get the singleton bean from the cache. For the singleton bean, the entire IOC container is created only once
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			// Get the instance object of a given bean, mainly to complete the relevant processing of factorybean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			//There are no singleton bean s in the cache
			//If we have created this bean instance,
			//However, the instantiation of the object failed due to the problem of circular reference
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			//Check whether there is a BeanDefinition with the specified name in the ioc container. Check it first
			// The required Bean can be obtained from the current BeanFactory. If it cannot delegate the parent class of the current container
			// Find it. If it is not found yet, find the parent container along the inheritance system of the container (normally, this parentBeanFactory must be null)
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					//The delegate parent container looks up based on the specified name and explicit parameters
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					//The delegate parent container looks up based on the specified name and type
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}

			// Whether the created Bean needs type verification is generally not required
			if (!typeCheckOnly) {
				// The Bean specified by the container tag has been created
				markBeanAsCreated(beanName);
			}

			try {
				// It mainly solves the problem of merging public attributes of subclasses and parent classes during Bean inheritance
				RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// Gets all beans that the current Bean depends on
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//Recursively call the getBean method to obtain the dependent bean of the current bean
						registerDependentBean(dep, beanName);
						try {
							//Register the dependent Bean with the currently dependent Bean
							getBean(dep);
						}
						
					}
				}

				// Create bean instance.
				if (mbd.isSingleton()) {
					// Here, an anonymous inner class is used to create a bean instance object and register it with the dependent object
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// Create an instance object of the specified bean. If there is parent inheritance, merge the definitions of the child class and the parent class
							return createBean(beanName, mbd, args);
						}
				
					});
					// Gets the instance object of the given Bean
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				// If it is a prototype pattern bean object
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						// Callback beforePrototypeCreation method. The default function is to register the currently created prototype object
						beforePrototypeCreation(beanName);
						// Create bean
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						//Callback the afterPrototypeCreation method. The default function tells the IOC container that the prototype object of the specified Bean is no longer created
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				//If the Bean to be created is neither a singleton pattern nor a prototype pattern, it is defined in the resource according to the Bean
				//Select the appropriate method to instantiate the Bean, which is used in Web applications
				//More commonly used, such as request, session, application and other life cycles
				else {
					String scopeName = mbd.getScope();
					if (!StringUtils.hasLength(scopeName)) {
						throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
					}
					Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
				
				}
			}
			
		}

		// Check if required type matches the type of the actual bean instance.
		// Type check the created bean instance object
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
		}
		return (T) bean;
	}

This doGetBean is too long. Let's simplify it:

protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		// Define an object to store the Bean to be returned
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		//First get the singleton bean from the cache. For the singleton bean, the whole IOC container is created only once
		//doGetBean1
		Object sharedInstance = getSingleton(beanName);
		//doGetBean2
		if (sharedInstance != null && args == null) {
			// Get the instance object of a given bean, mainly to complete the relevant processing of factorybean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		else {
			//There are no singleton bean s in the cache
			//If we have created this bean instance,
			//However, the instantiation of the object failed due to the problem of circular reference
			//doGetBean3
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
				// Create bean instance.
				//doGetBean4
			if (mbd.isSingleton()) {
				// Here, an anonymous inner class is used to create a bean instance object and register it with the dependent object
				sharedInstance = getSingleton(beanName, () -> {
					try {
						// Create an instance object of the specified bean. If there is parent inheritance, merge the definitions of the child class and the parent class
						return createBean(beanName, mbd, args);
					}
				});
			}
		}
		return (T) bean;
	}

Next, we will analyze the marked doGetBean

doGetBean1:getSingleton

spring checks whether the beanName has been manually registered in the singleton pool before creating a bean. This is the first time

Initialization, must be null

To sum up, Object sharedInstance = getSingleton(beanName); At present, it is mainly used to judge whether the bean is in the container when spring initializes the bean; And for programmers to get a bean directly.

Note that the author uses the word "present" here; Because getSingleton(beanName); This method has a lot of code; The logic in it is the most important code to realize circular dependency. I will go back to the full meaning of this method below;

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

Next, we will analyze doGetBean2

//doGetBean2
		if (sharedInstance != null && args == null) {
			// Get the instance object of a given bean, mainly to complete the relevant processing of factorybean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

Since sharedInstance = =null will not enter the if branch, then what time is it not equal to null?

1. After spring initialization, the sharedInstance obtained when the programmer calls getBean("x") is not equal to null;

2. In the case of circular dependency, it is not equal to empty when the object is obtained for the second time; For example, X depends on Y; Y depends on X; When spring initializes, X must be equal to null at the first execution, and then execute down. When y is injected into the attribute, y will also execute here. Then y is also null, because y is not initialized, y will also execute down. When y is injected into the attribute, obtain X in the acquisition container, that is, obtain x at the second execution; At this time, X is not empty; As for the specific reasons, the reader will read on

As for what this method does, don't analyze it. Just post the source code and let's have a look

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		//If the bean is not a factory, do not let the calling code try to dereference the factory.
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
		}
		//Now we have a bean instance, which can be a normal bean or FactoryBean.
		//If it is a FactoryBean, we will use it to create a bean instance unless
		//The caller actually wants a factory reference number
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

We then analyze doGetBean3

When spring creates bean s again, both singletons and prototypes will be add ed to this collection, and will be remove d after creation

Then analyze doGetBean4

if (mbd.isSingleton()) {
					// Here, an anonymous inner class is used to create a bean instance object and register it with the dependent object
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// Create an instance object of the specified bean. If there is parent inheritance, merge the definitions of the child class and the parent class
							return createBean(beanName, mbd, args);
						}
					});
					// Gets the instance object of the given Bean
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

Here, getSingleton is called again. If you have the impression, getSingleton is also called once. This is a method overload. The two getSingleton methods are not the same method. Readers can read the parameters themselves. In order to distinguish, this is called the second call to getSingleton; The above is called the first call to getSingleton;

Of course, the second getSingleton will create our bean. In other words, how the whole bean is initialized is in this method.

Next, we will study the content of the second getSingleton method, because I said that the whole bean initialization process is reflected in it;

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// Call createBean
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

Similarly, delete this Code:

public Object getSingleton(String beanName, ObjectFactory<?> 
singletonFactory) {
	//getSingleton2 -1
	Object singletonObject = this.singletonObjects.get(beanName);
			//getSingleton2 -2
			if (singletonObject == null) {
				//getSingleton2 -3
				if (this.singletonsCurrentlyInDestruction) {
					throw new Exception(beanName,
							"excepition");
				}
				//getSingleton2 -4
				beforeSingletonCreation(beanName);
				//getSingleton2 -5
				singletonObject = singletonFactory.getObject();	
			}
			return singletonObject;
		}
		

//getSingleton2 -2 , start parsing

if (singletonObject == null) {
As explained above, in spring initialization bean It must be empty when you are here, so it is established

//getSingleton2 -3 start parsing

if (this.singletonsCurrentlyInDestruction) {
			throw new Exception(beanName,
					"excepition");
		}

This line of code is actually relatively simple to judge whether the currently instantiated bean is in the destroyed collection; spring is cumbersome in the process of destroying or creating a bean. It will first put them into a collection to identify whether they are being created or destroyed; So if you understand the previous one that is creating a collection, then you understand the one that is destroying; But it doesn't matter if you don't understand it. These sets will be analyzed below;

If a bean is being created but some are being destroyed, an exception will occur; Why is this happening? In fact, it is also very simple. Multithreading may be;
 

//getSingleton2 -4 hypothesis parsing

beforeSingletonCreation(beanName);

This code is more important. It is about the collection being created and destroyed; This code can be explained, so if you don't understand the meaning of the collection above, use the spring source code to explain it here; Let's look at the context when the code is executed here

When spring thinks it can start to create beans, it first calls beforeSingletonCreation(beanName); Judge whether the bean currently being instantiated exists in the collection being created. In other words, judge whether it is currently being created; No matter whether spring creates a prototype bean or a singleton bean, when it needs to formally create a bean, it will record that the bean is being created (add to a set set); Therefore, before formally creating the bean, he should check whether the bean is being created (whether it exists in the collection); Why should spring judge whether this collection exists? There are many reasons, except that you can think of (what you can think of basically won't appear, such as concurrency and repeated creation, because it has done strict concurrency processing). In fact, this collection is mainly for circular dependency services. How can it be served? Take your time. First, let's take a look at the details of this line of code

protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) &&
				// Add beanName to this map
				!this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

//getSingleton2 -5 start analysis

singletonObject = singletonFactory.getObject();
Some readers may have forgotten how the singletonFactory object came from; Post the code again

ObjectFactory<?>  singletonFactory = new ObjectFactory(){
	public Object getObject(){
		//In fact, this is an abstract class and cannot be instantiated
		//createBean is implemented by subclasses. I don't care here
		//You understand that this is not an abstract class
		AbstractBeanFactory abf = new AbstractBeanFactory();
		Object bean = abf.createBean(beanName, mbd, args);
		return bean;
	};
};
//Pass in beanName and singletonFactory objects
sharedInstance = getSingleton(beanName,singletonFactory);

singletonFactory.getObject(); The GetObject method in the above code is called, in other words, ABF createBean(beanName, mbd, args); Return the created bean; So far, the second getSingleton method ends, and the bean passes through singletonfactory getObject(); Call createbean to complete the creation; Next, analyze the source code of createbean and continue to explore the principle of circular dependency;
In the AbstractAutowireCapableBeanFactory#createBean() method, the doCreateBean method is invoked to create bean.

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		//BeanWrapper is used to hold the created bean object
		BeanWrapper instanceWrapper = null;
		// If it is a singleton, clear the bean s with the same name in the cache first
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		//Call Postprocess postprocessor
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// Cache the Bean object of singleton mode in the container to prevent circular reference
		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");
			}
			//This is an anonymous inner class. In order to prevent circular reference, hold the reference of the object as soon as possible
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		//Initialization of bean object, dependency injection is triggered here
		//After initialization, this exposedObject is returned as a Bean after dependency injection
		Object exposedObject = bean;
		try {
			// Encapsulate the bean instance object, and assign the attribute configured in the bean definition to the instance object
			populateBean(beanName, mbd, instanceWrapper);
			//Initialize bean object
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			// Gets the registered singleton pattern Bean object with the specified name
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				//The registered Bean obtained by name is the same as the Bean being instantiated
				if (exposedObject == bean) {
					//Initialization of the currently instantiated bean is complete
					exposedObject = earlySingletonReference;
				}
				//The current bean depends on other beans, and new instance objects are not allowed when circular references occur
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		//Register the bean that completes dependency injection
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
instanceWrapper = createBeanInstance(beanName, mbd, args);

As the name suggests, createBeanInstance is to create an instance. Note that this is only to create an instance object, which cannot be called a bean, but an X object is created, and the attributes have not been filled in

How to create this one depends on me Instantiation process of Spring Bean

Then analyze

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));

This must be true. addSingletonFactory will be called

 

addSingletonFactory(beanName,singletonFactory); Add a singleton factory as the name suggests; In fact, we should pay great attention here, because when talking about spring circular dependency in most materials, it is said that a semi-finished bean is exposed in advance; I think this is not strict; It's even wrong. The so-called early exposure is add here, but we see that the source code does not add a bean, but adds a factory object - singletonfactory; What's the difference between the two statements? The difference is great, it's a world of difference; We analyze slowly; What's the difference between bean and factory? In the current context, beans are x objects that have gone through the spring life cycle; The so-called semi-finished bean may not have experienced a complete life cycle; What about factory objects? If you go to the source code of ObjectFactory, or directly as the name suggests, it is a factory that can generate objects, or a factory that can generate beans; In other words, a bean is a product, and a factory is the company that produces these products; If you can't understand it, it may be easy to understand it - the difference between ice fire and the whole set. Ice fire is an item in the whole set, and there are other items besides ice fire;

spring adds a singletonFactory object here (this factory can generate semi-finished objects), not a semi-finished object; The equivalent of adding here is a complete set, not ice and fire; In the future, it will be obtained from the factory, and then semi-finished products will be obtained through the factory; What will come out in the future is a complete set. You can choose a project arbitrarily in the complete set; I don't know. I didn't explain the problem clearly;

Of course, after all this, maybe you still don't understand why you need to add this factory object here? And where is add going?

Let's first analyze where the bean factory object add goes and check the source code

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

First level cache: there may be many beans, such as various built-in beans in spring, such as other created beans in your project, but in the process of creating X, there is absolutely NO X bean in the first level cache and it is useless y; Because spring creates beans in alphabetical order by default;

Level 2 Cache: there is only one factory object in it, the corresponding key is the beanName of X, and the GetObject method of this bean factory object can return x (x bean of semi-finished product) at this time
After the put is completed, the code is executed next;

L3 cache: let's say there's nothing in it

populateBean(beanName, mbd, instanceWrapper);

populateBean is a well-known method. It mainly completes attribute injection, which is often called automatic injection; Assuming that the code in this environment runs this line of code, y will be injected, and Y refers to x, so the injected y object also completes the injection of X; What do you mean? First, take a look at the situation before populateBean is not executed

If X is instantiated before populateBean is executed and Y is not instantiated, y cannot be injected; Next, let's look at the situation after executing this line of code


x filling y (xpy for short) must first obtain y and call getBean(y). The essence of getBean has been analyzed above. After entering the first call to getSingleton, readers can recall that in my explanation of the name of doGetBean method above, it is said that this method is used to create beans and obtain beans;

For the first time, getSingleton will get y from the singleton pool. If y does not have a singleton pool, it will start to create y

Y as like as two peas in creating x, will take the bean life cycle. For example, add y to the collection of beans being created, infer the construction method, instantiate y, expose the factory object in advance (there are now two factories in the L2 cache, X and Y respectively), etc.... Repeat the steps of X;

 

//TODO hasn't been in good shape recently. Please make it up later

Keywords: Spring

Added by ron8000 on Mon, 24 Jan 2022 09:48:18 +0200