Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Why does Spring need three-level cache to solve circular dependency

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Today, I would like to share with you why Spring needs three-tier cache to solve circular dependencies. The content is detailed and the logic is clear. I believe most people still know too much about this, so share this article for your reference. I hope you can get something after reading this article. Let's take a look at it.

Bean lifecycle

First of all, you need to understand the life cycle of bean in spring and the loading process of bean in spring, so that you can understand more clearly how spring solves circular dependencies.

We listed a lot of interfaces in the BeanFactory factory of spring, representing the life cycle of bean. What we mainly remember is the interfaces I circled in red lines, and then combined with the source code of spring, we can see where these interfaces are mainly called.

The doCreateBean method of the AbstractAutowireCapableBeanFactory class is the beginning of creating the bean. We can see that we first need to instantiate the bean, that is, to open up a memory space for the object in the heap. The logic in the createBeanInstance method is probably to use reflection to generate the instance object, which means that the object has not yet been populated with attributes, that is, the attributes annotated by @ Autowired have not been injected.

We can see that the second step is to populate the member attributes of bean. The logic in the populateBean method is to inject annotations that use the injection attributes. If it is found that the injected object has not been generated during the injection process, it will run to produce the object to be injected. The third step is to call the initializeBean method to initialize the bean, that is, to call the interface we mentioned above.

You can see that in the initializeBean method, the method that uses the Aware interface is called first. Let's take a look at those methods in the invokeAwareMethods method that will call the Aware interface.

We can know that if we implement the three Aware interfaces of BeanNameAware,BeanClassLoaderAware,BeanFactoryAware, we will call the setBeanName (), setBeanClassLoader (), setBeanFactory () methods in turn, and then look at the applyBeanPostProcessorsBeforeInitialization source code.

It is found that if a class implements the BeanPostProcessor interface, the postProcessBeforeInitialization method will be executed. It should be noted here that if multiple classes implement the BeanPostProcessor interface, then multiple implementing classes will execute the postProcessBeforeInitialization method. You can see that the for loop executes in turn. Another point to note is that if class An is loaded into the spring container, class An also overrides the postProcessBeforeInitialization method of the BeanPostProcessor interface. Note that the postProcessBeforeInitialization method of class A will not be executed. Because class A has not been loaded yet, it has not been fully placed in spring's singletonObjects level 1 cache.

Look at one more point of attention.

You can see that ApplicationContextAwareProcessor also implements the BeanPostProcessor interface, rewrites the postProcessBeforeInitialization method, and calls the invokeAwareInterfaces method in the method, while the invokeAwareInterfaces method also says that if many Aware interfaces are implemented, the corresponding methods will be executed in turn. It is worth noting that the setApplicationContext method of the ApplicationContextAware interface, and take a look at the invokeInitMethods source code.

It is found that if the InitializingBean interface is implemented and the afterPropertiesSet method is overridden, the afterPropertiesSet method will be called. Finally, whether the init-method is specified or not can be specified through the tag or the initMethod annotated by @ Bean. Finally, look at an applyBeanPostProcessorsAfterInitialization source code diagram.

It is found that similar to the previous postProcessBeforeInitialization method, it also iterates through the interface implementation class of BeanPostProcessor and executes the postProcessAfterInitialization method. The life execution flow of the entire bean is shown in the screenshot above, where the method of which interface is called, and the execution flow of the method.

Finally, the life process of bean is summarized by a flow chart.

Three-level cache to solve circular dependence

The previous section makes an overall process analysis of the life cycle of bean, which is very helpful to spring on how to solve circular dependencies. When we analyzed the populated attributes earlier, if we found that the attributes had not been generated in spring, we would run to generate an instance of the attribute object.

We can see that when filling attributes, spring exposes the instantiated bean through ObjectFactory semi-finished product in advance. Why it is called semi-finished product is because the bean object is instantiated at this time, but it is not populated with attributes, so it is an incomplete bean instance object.

Spring uses singletonObjects, earlySingletonObjects, and singletonFactories caches to solve the problem. The cache actually means three Map.

You can see the objects saved by the third-level cache. Here, we focus on the second-level cache earlySingletonObjects and the third-level cache singletonFactory, while the first-level cache can be ignored. As we mentioned earlier, the instantiated bean will be exposed to the tertiary cache in advance through the ObjectFactory semi-finished product.

SingletonFactory is an anonymous inner class passed in, and a call to ObjectFactory.getObject () ends up calling the getEarlyBeanReference method. Let's take a look at how other semi-finished instance objects are taken in circular dependencies.

Let's suppose there is a scenario where AService depends on BService,BService, depends on AService.

1. AService is first instantiated, and the instantiation is exposed to the tertiary cache through the ObjectFactory semi-finished product.

two。 Populate the property BService and find that BService has not been loaded yet, and will load BService first.

3. In the process of reloading BService, the instantiation is also exposed to the third-level cache through the ObjectFactory semi-finished product.

4. When you populate the attribute AService, you can get the semi-finished ObjectFactory from the three-tier cache

After getting the ObjectFactory object, calling the ObjectFactory.getObject () method will eventually call the getEarlyBeanReference () method. The main logic of the getEarlyBeanReference method probably describes that if bean is proxied by AOP, the beanProxy object is returned, and if it is not proxied, the original bean instance is returned. At this time, we will find that we can get the bean instance (the attribute is not populated), then remove it from the third-level cache and put it into the secondary cache earlySingletonObjects. At this time, B injects a semi-finished instance An object, but as B initializes, A will continue with subsequent initialization operations, and eventually B will inject a complete An instance, because they are the same object in memory. The following is the key point. We find that this secondary cache seems to be a bit redundant, as if it can be removed, and only the first and third levels of cache can solve the problem of circular dependency.

As long as two caches can really solve the problem of circular dependency, there is a premise that the bean is not proxied by AOP. If the bean is proxied by AOP, then using only two caches cannot solve the problem. Let's take a look at the scenario in which bean is proxied by AOP.

We find that the testAopProxy of AService is proxied by AOP to see what object is returned by the getEarlyBeanReference of the anonymous inner class passed in.

It is found that singletonFactory.getObject () returns a proxy object for AService or is proxied by CGLIB. Check whether the proxy object returned by singletonFactory.getObject () is the same AService again.

We will find that executing the singleFactory.getObject () method again is a new proxy object, which will be a problem, because AService is a singleton, and each execution of the singleFactory.getObject () method will generate a new proxy object, assuming that there are only first-and third-level cache, every time I get the singleFactory object from the third-level cache, executing the getObject () method will produce a new proxy object, which is not possible, because AService is a singleton. So here we need to solve this problem with the help of secondary cache, putting the objects generated by singleFactory.getObject () into the secondary cache, and then going to the secondary cache to get it. There is no need to execute the singletonFactory.getObject () method again to generate a new proxy object to ensure that there is only one proxy object at all times. There is another point to pay attention to.

Since singleFactory.getObject () returns a proxy object, the injection should also be a proxy object, and we can see that what is injected is indeed an AService object that has passed through the CGLIB proxy. Therefore, if there is no AOP, two-level cache can solve the problem of circular dependency. If you add AOP, two-level cache cannot be solved, and it is impossible to generate a new proxy object for me every time the singleFactory.getObject () method is executed, so we have to use another cache to save the resulting proxy object.

These are all the contents of the article "Why Spring needs three-level caching to solve circular dependencies". Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report