I Clarify the problems that need to be clarified
- The acyclic process of ordinary beans depends on the bean life cycle
- The non cyclic dependency of aop proxy bean is the process of bean life cycle
- The cycle of ordinary beans depends on the process of bean life cycle
- The circulation of aop proxy bean depends on the process of bean life cycle
It's easy to figure out the four questions and then answer the circular dependency of spring bean s
Step by step understanding is also easy to compare and understand
II The acyclic process of ordinary beans depends on the bean life cycle
1. Get bean
AbstractApplicationContext#getBean("a", A.class)
AbstractBeanFactory#doGetBean("a", A.class)
DefaultSingletonBeanRegistry#getSingleton("a", true) / / try to get the reference from the cache. True means that it is allowed to get the reference from the factory pool in advance. When getSingleton("a", true) is called for the second time in the same process, the early reference method in the factory method will be triggered and the proxy judgment will be triggered. Therefore, the early reference logic includes aop proxy generation logic, That is, referencing in advance does not necessarily generate an agent, but generating an agent in advance must be referenced in advance
If you can get the object from the cache, you don't have to complete the subsequent instantiation, property filling, initialization and aop proxy, because no matter what level of cache the object is obtained from, the subsequent steps are either completed (obtained from the first level cache), or the initialization is completed after the first property filling of the getBean() method of the bean, Anyway, other beans should not trigger getBean() to complete the subsequent initialization of the beans obtained from the cache
Time to add to semi-finished product pool
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); // Add to semi-finished product pool this.singletonFactories.remove(beanName); // Remove from factory pool } } } } return singletonObject; }
getSingleton method with createBean
// AbstractBeanFactory#doGetBean("a", A.class) sharedInstance = getSingleton(beanName, () -> { // ObjectFactory.getObject() try { return createBean(beanName, mbd, args); } }
2. Instantiation
AbstractAutowireCapableBeanFactory#doCreateBean
AbstractAutowireCapableBeanFactory#createBeanInstance: create instance
Add singleton factory pool
The only way to create an instance is to put the factory method applied in advance into the factory pool before property filling
if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // **Add singleton factory pool** 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); // Add to project pool this.earlySingletonObjects.remove(beanName); // Removal from semi-finished product pool this.registeredSingletons.add(beanName); // Register the container of the singleton beanName } } }
AbstractAutowireCapableBeanFactory#populateBean: Property fill
AbstractAutowireCapableBeanFactory#initializeBean: initializing
try { populateBean(beanName, mbd, instanceWrapper); // Attribute filling, key points of circular dependency exposedObject = initializeBean(beanName, exposedObject, mbd); // initialization }
3. Attribute filling
AbstractAutowireCapableBeanFactory#populateBean: Property fill
Attribute filling in annotation form
for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // Property filling code of javaconfig configuration PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } }
Attribute filling entry in xml form
if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs);// Attribute filling code of xml configuration }
4. Initialization
AbstractAutowireCapableBeanFactory#initializeBean: initializing
AbstractAutowireCapableBeanFactory#invokeAwareMethods: Aware interface call
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); // beanName } if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl); // ClassLoader } } if (bean instanceof BeanFactoryAware) { // beanFactory ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } } }
BeanPostProcessor#postProcessBeforeInitialization: call the post processor before initialization
Apply this BeanPostProcessor to a given new bean instance before any bean initialization callback, such as the afterpropertieset of InitializingBean or the custom init method
Abstractautowirecapablebeanfactory #invokeinitialmethods: initialization methods
InitializingBean's afterpropertieset or custom init method (@ PostConstructor or init method in xml configuration)
Call initializingbean After propertiesset then calls the custom initialization method
BeanPostProcessor#postProcessAfterInitialization: call the post processor after initialization
After any bean initialization callback (such as the afterpropertieset of InitializingBean or the custom init method), apply this BeanPostProcessor to the given new bean instance
AbstractAutoProxyCreator#postProcessAfterInitialization: method of handling aop implementation
this.earlyProxyReferences.remove(cacheKey) != bean // If it has been referenced in advance, the same bean instance will be returned, and then the proxy will not be generated repeatedly
5. Destruction method of registered one-time bean
AbstractBeanFactory#registerDisposableBeanIfNecessary
Register in the container of the one-time bean and register the destroy method
public void registerDisposableBean(String beanName, DisposableBean bean) { synchronized (this.disposableBeans) { this.disposableBeans.put(beanName, bean); } }
When to add to the singleton pool
DefaultSingletonBeanRegistry#addSingleton
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); // Remove from factory pool this.earlySingletonObjects.remove(beanName); // Remove from semi-finished product pool this.registeredSingletons.add(beanName); // Register the single instance beanName, Set set Set. Because it is called repeatedly, it must be a Set set Set } }
In this scenario, no bean s enter the semi-finished product pool
III The non cyclic dependency of aop proxy bean is the process of bean life cycle
- Get bean
- instantiation
- Attribute filling
- initialization
- Destruction method of registered one-time bean
Only when initializing, the process of calling the post processor after initialization is different. Other processes are the same as "the mid-term declaration of ordinary acyclic bean s". The post processor after initialization needs to generate an aop agent, return the agent, and finally put it directly into the singleton pool
In this scenario, no bean s enter the semi-finished product pool
IV The cycle of ordinary beans depends on the process of bean life cycle
The overall process is similar to the life cycle of ordinary beans. The difference is that property filling will trigger getBean operations of other beans
-
Get bean a(getBean(a))
-
Instantiation a
-
a attribute filling
-
Trigger getBean(b)
-
Instantiation b
-
b attribute filling
Trigger getBean(a): at this time, the factory pool hits, returns an ordinary bean instance, and completes the filling
-
b initialization
-
Method of one-time destruction of bean registration b
-
-
a initialization
-
a destruction method of registering one-time bean s
In this scenario, ordinary bean s enter the semi-finished product pool
V The circulation of aop proxy bean depends on the process of bean life cycle
Similar to the ordinary bean circular dependency scenario, the difference is that the factory method in the factory pool generates the aop proxy in advance, and there is no need to generate the proxy again after initialization
-
Get bean a(getBean(a))
-
Instantiation a
-
a attribute filling
-
Trigger getBean(b)
-
Instantiation b
-
b attribute filling
Trigger getBean(a): at this time, the factory pool hits and returns the bean instance of aop proxy to complete the filling
-
b initialization
However, instance b still generates aop proxy in * * post processor after initialization "* * because b is not the getBean that occurs in the cycle and will not hit the factory pool
-
b destruction method of registering one-time bean s
-
-
a initialization
**"Post processor after initialization" * * will no longer generate aop agent
-
a destruction method of registering one-time bean s
In this scenario, the proxy bean enters the semi-finished product pool
Vi Role of L3 cache
Summarize the timing of adding and removing L3 cache
When obtaining beans: the time to add the semi-finished product pool (only triggered when there is a circular dependency and there is a factory method in the factory bean)
After the instance is created and before the attribute is filled: when the factory pool is added, each bean that needs to be instantiated will execute this logic
After the initialization and one-time bean destruction method registration are completed: when the singleton pool is added, the bean instance is returned by the method, so the semi-finished product pool and factory pool are directly removed
Therefore, the bean reference will exist in the pool as follows
Therefore, we know that the bean instance reference must enter the factory pool, and finally into the singleton pool. Only in case of circular dependency can it enter the semi-finished product pool
Role of L3 cache
Singleton pool function: solve the problem of obtaining incomplete bean s
Role of semi-finished product pool: solve circular dependency and avoid multiple execution of aop agent
Function of factory pool: when creating an instance, you don't need to care about whether you are referenced circularly and whether you are represented (the premise of considering whether you are represented is circular reference) In case of circular dependency, the generation agent is handed over to the processing when the circular dependency occurs, so as to ensure the logical consistency of what cycle in a scenario
When a bean is first used by getBean, its execution process is always like this
Get bean > instantiate bean > bean attribute filling > initialize bean > post processor after initialization: if the agent has not been generated, aop bean needs to generate agent for it > register the destruction method of singleton bean
In addition, the method is put in the factory pool, not the bean instance, so a separate cache must also be used