Here is my own understanding, so as to prevent it from being forgotten in the future. If there is a wrong understanding of that place, please point it out.
1. Background
In the process of writing code, we generally use @Autowired
to inject another object, but sometimes it happens 循环依赖
, but our code does not report an error, what is the reason for this?
2. Preliminary knowledge
1. Consider the type of circular dependency
Here we consider the circular dependency of 单例
+ @Autowired
, without considering the injection of 构造器注入
or 原型作用域的Bean
.
2. When is the proxy object created?
Notice:
Under normal circumstances, that is, when there is no circular dependency, aop增强
is in the BeanPostProcessor#postProcessAfterInitialization
method after the bean initialization is completed, but if there is a circular dependency, it needs to be in advance, getEarlyBeanReference
Create proxy objects in advance.
3. What objects are stored in the L3 cache
cache field name | cache level | type of data | explain |
---|---|---|---|
singletonObjects | 1 | Map<String, Object> | What is saved is the complete Bean, that is, the Bean that can be used |
earlySingletonObjects | 2 | Map<String, Object> | The semi-finished Bean is saved, that is, the attribute has not been set, and the initialization work has not been completed. |
singletonFactories | 3 | Map<String, ObjectFactory<?>> | Mainly to generate beans, and then put them in the second level cache |
Notice:
ObjectFactory#getObject()
Each call will produce a new object or return the old one, depending on whether a proxy exists, etc.
4. Get objects from level 3 cache
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
5 Simplified creation process of Spring Bean
1. Instantiate a bean
Object bean = instanceWrapper.getWrappedInstance();
Instantiate a Bean or new Bean()
2. Add to the L3 cache
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
There are some conditions for adding to the third-level cache, and it is generally true. It is considered here that it needs to be added to the third-level cache.
3. Set the properties of the bean
populateBean(beanName, mbd, instanceWrapper);
The first step instantiates the bean, but at this time the properties that need to be injected are not filled, and the properties are filled through this step.
4. Initialize beans
Object exposedObject = initializeBean(beanName, exposedObject, mbd);
Initialize Bean, execute initialization method, Aware callback, execute BeanPostProcessor#postProcessAfterInitialization method ( aop的增强
is implemented in this)
If there is 循环引用
, the enhancement of aop needs to be advanced.
5. Add to the first level cache
addSingleton(......)
3. Understanding
@Component
class A {
@Autowired
private B b;
}
@Transaction (存在代理)
@Component
class B{
@Autowired
private A a;
}
1. Suppose that only singletonObjects and earlySingletonObjects can complete circular dependencies
cache field name | cache level | type of data | explain |
---|---|---|---|
singletonObjects | 1 | Map<String, Object> | What is saved is the complete Bean, that is, the Bean that can be used |
earlySingletonObjects | 2 | Map<String, Object> | The semi-finished Bean is saved, that is, the attribute has not been set, and the initialization work has not been completed. |
At this time, it is necessary to obtain an instance of B
177fcd7210a476c0321f4c1a685f5fba---, that is, getBean("b")
, which can be seen from the simplified process of Bean learned above.
As can be seen from the above figure, 对象存在代理时
, the level 2 cache cannot solve the problem. Because the proxy object is done by BeanPostProcessor
, 是在设置属性之后才产生的代理对象
.
At this point, some people may say, if I immediately perform Aop proxy after building the instance of B, won't this solve the problem? That assumes that there is no circular dependency between A and B, will this design be inelegant?
2. Suppose that only singletonObjects and singletonFactories can complete circular dependencies
It can be seen from the figure that it is not possible.
3. How to implement level 3 cache
1. Solve the proxy problem
Because by default, the proxy is completed by BeanPostProcessor
, in order to solve the proxy, it is necessary to create the proxy in advance, then the creation of the proxy is placed in the level 3 cache for creation.
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
getEarlyBeanReference
This method will return the proxy bean
2. Solve the inconsistency of the value obtained by the singleton through the third-level cache multiple times
As can be seen from the above figure, the object is first searched from 一级->二级->三级缓存
. When the object is generated in the third-level cache, it is put into the second-level cache and cached, and the third-level cache is deleted at the same time.
3. Flowchart
4. Summary
1. The first level cache singletonObjects
stores singletons that can be used.
2. The second-level cache earlySingletonObjects
stores the early beans, that is, semi-finished products, which are still unavailable at this time.
3. The L3 cache singletonFactories
is an object factory, which is used to create objects and put them into the L2 cache. At the same time, if the object has an Aop proxy, the object factory returns the proxy object.
Can the created proxy object be stored directly in earlySingletonObjects
? This can solve the problem, but the design may not be reasonable. Because in Spring Aop
the proxy is created after the object is finished. And if there is no circular dependency, is it necessary to create proxy objects in advance? Divided into three-level cache, the code structure is clearer and more reasonable.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。