Spring source code analysis-Spring cache and circular dependency issues

Preface

From the analysis of the previous article, we can see that there are more links in the process of creating and instantiating beans in spring and the packaging is deeper. If so many links are needed every time getBean, then not only will it produce a lot of memory objects and calculation logic , And more importantly, it is unable to solve the dependency problem of objects in some scenes, especially the problem of circular dependency. Therefore, spring itself takes this issue into consideration, and there will be some related cache designs in the process of creating beans. Today we will take a look at how it is solved by caching.

Cache scene

Scenario 1. When
Spring source code analysis-Spring cache and circular dependency issues
getting a bean for the first time with getBean(), it will be obtained from the first-level or second-level cache according to the process in the above figure, and it will be returned directly if it is obtained. If not, take it directly from the third-level cache. When there is a cached object in the third-level cache, get the bean directly through the cached beanFactory.getObject(), and remove the third-level cache and write the obtained bean to the second-level cache. Cache, and then return the object.
Spring source code analysis-Spring cache and circular dependency issues
Spring source code analysis-Spring cache and circular dependency issues
Scenario 2.
Spring source code analysis-Spring cache and circular dependency issues
Spring source code analysis-Spring cache and circular dependency issues
During the doCreateBean() process at the first createBean() , if the bean settings can be exposed in advance (enabled by default), a third-level cache (beanFactory object)
Spring source code analysis-Spring cache and circular dependency issues
Spring source code analysis-Spring cache and circular dependency issues
will be created . Why is the second-level cache removed when the third-level cache is created? Cache? Because the objects in the second-level cache are obtained from the third-level cache, when the third-level cache is updated, the old second-level cache data will be removed at the same time to avoid the problem of inconsistent cache data.

Circular dependency

In the A object, the reference to the B object is held; in the same way, in the B object, the reference to the A object is also supported. This kind of circular dependency is divided into two situations: 1. In the A object, the B object is used as a member variable of the A object; 2. In the A object, the B object is dependent on the construction parameter of the A object. Once the two methods have mutual influence The reference scene of the ring needs attention.
Spring source code analysis-Spring cache and circular dependency issues
The above screenshot belongs to the first case, and Spring only considers this case. In this case, spring is regarded as a normal reference. In other cases, spring does not support it and will directly throw an exception in this case.
Spring source code analysis-Spring cache and circular dependency issues
Spring source code analysis-Spring cache and circular dependency issues

solution

So how does spring solve the first circular dependency situation above? This problem is perfectly solved by constructing a three-level cache mechanism. For the specific solution process, please see the following flowchart.
Spring source code analysis-Spring cache and circular dependency issues
According to the above solution flowchart and the posted cache source code, the detailed explanation is as follows:

  1. When CircularRefA is instantiated, first get the instance bean from the cache;
  2. When there are no objects in the three levels of cache, call getSingleton() to create an instance;
  3. Call the anonymous class to create an instance createBean();
  4. Instantiate the CircularRefA object through the constructor (the dependency properties and members in the object are not instantiated, that is, the CircularRefB object is null at this time);
  5. Create a third-level cache to cache the objectFactory object corresponding to CircularRefA;
  6. Perform dependency injection on CircularRefA, and then trigger the getBean() operation of the CircularRefB object;
  7. The program recursively enters step 1...step 6;
  8. When the same goes to step 6, perform dependency injection on CircularRefA in CircularRefB to trigger the getBean() operation;
  9. At this time, a reference to CircularRefA can be obtained from the third-level cache (although it is only a skeleton), so CircularRefA is injected;
  10. Immediately after the instantiation of CircularRefB is completed, it is then assigned to the CircularRefB member variable in CircularRefA through dependency injection;
  11. In the end, the two objects, CircularRefA and CircularRefB, are instantiated (they hold each other's references, and they will also be assigned at this time);

OK, do you understand here? Spring's three-level cache mechanism design is very interesting. Those who are interested can go to the source code.
Finally, we must make a clear conclusion: only beandefintion's Scope=Singleton type can perform caching and support the circular dependency of the first case above. As long as other types of circular dependencies occur, spring directly throws an exception. As to why spring does not support the source code in other cases, you can think of it more or less.

Concluding remarks

The issue about spring caching and circular dependencies is shared here first. If you have any questions about this, you can leave a message directly in the comment area. Please continue to pay attention to more dry goods of spring source code!

Guess you like

Origin blog.51cto.com/14815984/2532622