What are circular dependencies
Simply put, A depends on B, and B depends on A
In detail, circular dependencies are created like this:
- First create object A, instantiate object A, at this time object A property B is empty, fill property B
- Look for B objects in the container, if found, direct assignment does not have the problem of loop dependency, not find B objects directly
- Instantiate object B with property A empty and fill property A
- Select object A from container, create object A
In this case, the diagram is A closed loop, and if you want to solve the problem, you have to make sure that you don’t have to create A again, that is, when you get A from the container, you have to be able to get it.
In Spring, object creation can be divided into instantiate and initialize, instantiation good but did not complete the initialization of objects can be directly to other object references, so can do one thing at this time, the complete instantiation but not initialized object exposed out, let other objects can be reference, completes the closed-loop power network operation.
How do I solve circular dependencies
At this point, if will ponder, will find A object exists, but at this time of A object is not A complete state, only completed the instantiation but unfinished initialization, if in the process of program calls, have an object reference, can be completed in late to his assignment operation, can give priority to the nonholonomic state object assignment priority, Waiting for subsequent operations to complete the assignment exposes a reference to an incomplete object in advance, so the core of the solution is to separate instantiation and initialization. This is also the key to solving the problem of loop dependency.
When all the objects are complete instantiation and after initialization, but also put full objects in the container, the container at this time objects exist in the several states, complete instantiation = but not initialized, complete state, because in the container, so will use different map structure for storage, where there will be a level 1 cache and the second level cache, If there are objects with the same name in level 1 cache, then there are no objects with the same name in level 2 cache, because they are looked up in the order of 1, 2, and 3. Level 1 cache holds complete objects and level 2 cache holds non-complete objects
Spring uses a three-level cache to address circular dependencies
Spring uses three levels of caching to solve the problem of loop dependencies, namely three maps:
The first level cache, SingletonObjects, holds Bean objects that have gone through a full life cycle
The second level cache, earlySingletonObjects, holds early exposed Bean objects whose life cycle has not expired (properties have not been filled)
The third level cache, singletonFactories, stores factories that can generate beans
Description of the migration of objects A and B in the three-level cache
- B is needed during the creation of A, so A instantiates B by putting itself in A level 3 cache
- When B instantiates, it finds that it needs A, so IT looks at level 1 cache, no, it looks at level 2 cache, no, it looks at level 3 cache, finds A, puts the A in level 3 cache in level 2 cache, and deletes the A in level 3 cache
- B is successfully initialized, puts itself in level 1 cache (A in B is still being created), and then goes back to create A. At this point, B is finished creating, takes B directly from level 1 cache, completes the creation, and puts itself in level 1 cache
You can’t just use two level cache lines
Cyclic dependencies can be resolved when only the second level cache is used. An error is reported after adding an AOP implementation
Level 2 caching is designed to solve the problem of cyclic dependencies that arise during AOP proxying, and is sufficient to solve the problem without AOP