Java interview must ask, let you thoroughly understand how spring solves circular dependencies

content

1. What is circular dependency

2. How does Spring solve circular dependencies

1. The third-level cache of singleton beans in Spring

2. The life cycle of Beans in Spring

3. The main method of Bean initialization

3. Why use L3 cache

1. Use the first level cache

2. Use the second level cache

a) use singletonObjects and earlySingletonObjects

b) using singletonObjects and singletonFactories


1. What is circular dependency

Multiple beans depend on each other, forming a closed loop. For example: A depends on B, B depends on c, and c depends on A

Generally speaking, if you ask how to solve the circular dependency inside the spring container, it must refer to the scene where the properties refer to each other in the default singleton bean. That is to say, Spring's circular dependency is a problem that occurs when the Spring container is injected.

2. How does Spring solve circular dependencies

1. The third-level cache of singleton beans in Spring

The first level cache (also called singleton pool) singletonObjects: store Bean objects that have gone through a complete life cycle

The second-level cache: earlySingletonObjects, which stores the Bean objects exposed early, the life cycle of the Bean is not over (the properties are not yet filled)

The third-level cache: Map<String, ObiectFactory<?>> singletonFactories, which stores factories that can generate beans

2. The life cycle of Beans in Spring

3. The main method of Bean initialization

getSingleton: I hope to get a singleton bean from the container. If not, doCreateBean: If not, create a beanpopulateBean: After it is created, fill in the attribute addSingleton: After filling, add it to the container for use. 4, specific instructions

A needs B during the creation process, so A puts itself in the third-level cache. When instantiating BB, it finds that A is needed, so B first checks the first-level cache, if there is no, then checks the second-level cache, still no, then Check the third-level cache, find A, then put the A in the third-level cache into the second-level cache, delete the AB in the third-level cache and successfully initialize it, and put itself in the first-level cache (at this time, the A in B A is still in the state of being created) and then come back and create A. At this time, B has been created, get B directly from the first-level cache, then complete the creation, and put A in the first-level cache.

3. Why use L3 cache

1. Use the first level cache

Instantiate A -> put the semi-finished product A into singletonObjects -> find that B cannot be obtained when filling the properties of A -> instantiate B -> take out A from singletonObjects and fill the properties of B -> put finished product B into singletonObjects - > populate B into A's properties -> put finished A into singletonObjects.

Problem: This basic process is common, but if another thread wants to fetch A during the whole process, it may only get a semi-finished product A with null attributes, which will cause problems.

2. Use the second level cache

a) use singletonObjects and earlySingletonObjects

The finished product is placed in singletonObjects, and the semi-finished product is placed in earlySingletonObjects

The process can go like this: instantiate A -> put the semi-finished product A into earlySingletonObjects -> find that B cannot be obtained when filling the properties of A -> instantiate B -> put the semi-finished product A into earlySingletonObjects -> from earlySingletonObjects Take out A and fill B's properties -> put finished product B into singletonObjects, and delete B from earlySingletonObjects -> fill B into A's properties -> put finished product A into singletonObjects and delete earlySingletonObjects.

Problem: Such a process is thread-safe, but if an aspect (AOP) is added to A, this approach will not meet the needs, because the primitive objects stored in earlySingletonObjects are all original objects, and what we need to inject is actually A's proxy object.

b) using singletonObjects and singletonFactories

The finished product is placed in singletonObjects, and the semi-finished product is obtained through singletonFactories

The process is as follows: instantiate A -> create an object factory of A and put it into singletonFactories -> find that B cannot be obtained when filling the properties of A -> instantiate B -> create an object factory of B and put it into singletonFactories - > Get A's object factory from singletonFactories and get A to fill in B -> put finished product B into singletonObjects, and delete B's object factory from singletonFactories -> fill B into A's properties -> put finished product A in into singletonObjects and delete A's object factory.

Problem: This process is also suitable for ordinary IOC and concurrent scenarios, but if an aspect (AOP) is added to A, this situation cannot meet the requirements.

Guess you like

Origin blog.csdn.net/weixin_44302240/article/details/124194495
Recommended