三级缓存与循环引用
# 三级缓存与循环引用
# 三级缓存
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
2
3
4
5
6
7
8
一级缓存singletonObjects用于存放创建好的单实例Bean
二级缓存earlySingletonObjects用于存放早期暴露的单实例Bean,是一个半成品
三级缓存singletonFactories存放的是获得一个实例化Bean的函数(ObjectFactory是一个FunctionalInterface类),这个函数会执行后置处理器SmartInstantiationAwareBeanPostProcessor的后置处理方法,对早期实例化还没有初始化的Bean进行干预。生成这个类的代理类。
# 结合源码查看三级缓存的使用
首先spring通过getBean方法获取Bean
在AbstractBeanFactory#doGetBean方法中,先尝试从缓存中获取Bean,如果能获取到,那么就不用再创建了。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//缓存中获取
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//获取实际的Bean,对于工厂Bean,要到工厂Bean的缓存中获取真实的Bean,如果没有,通过FactoryBean.getObject方法获取真实Bean,并放入缓存
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else { ... }
// Check if required type matches the type of the actual bean instance.
//类型检查
if (requiredType != null && !requiredType.isInstance(bean)){ ... }
return (T) bean;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
查看从缓存中获取Bean的方法,最终调用方法如下
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从一级缓存中获取已经创建的单实例Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//一级缓存中没有,去二级缓存中查看是否有早期暴露的Bean
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//二级缓存中也没有,查看三级缓存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//如果三级缓存中有,此时得到的是一个能够获得早期实例的函数,通过执行该函数,可以得到早期暴露的实例化Bean
singletonObject = singletonFactory.getObject();
//将执行函数后得到的实例化Bean放到二级缓存,这样如果后面再使用到早期暴露的实例,就可以在二级缓存中获取到,而不是再次执行三级缓存中的函数
//因为三级缓存的函数会执行一些后置处理方法,例如AOP代理会生成一个早期实例的代理实例,如果重复执行,那么就获取了新的代理,就没法保证单例性质。
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
如果三级缓存都没有获得Bean,那么就需要进入Bean的创建流程 将正在的创建流程封装成函数方法,在getSingleton中执行该函数方法创建Bean,getSingleton方法会对创建好的Bean做一些其他处理,这个下文还会提到。
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
先看createBean方法
spring会先用Bean的构造方法实例化一个Bean,此时Bean还没有初始化,我们叫他早期Bean。
先将早期Bean封装成可以执行后置处理的函数,放到三级缓存中
然后再进入Bean的初始化流程
然后再次从缓存中获取,这时一二级缓存中是没有实例的,只有三级缓存中存放了可以获取实例的函数
执行这个函数,从三级缓存中获取Bean,并放到二级缓存。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
//使用构造函数创建实例
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//放入三级缓存
//所以Bean是先实例化,然后封装成函数,放入三级缓存的。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
//初始化Bean 自动装配,执行初始化方法等
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
...
}
if (earlySingletonExposure) {
//这里传入的是false,如果二级缓存中也为空,说明三级缓存中的函数没有被调用过,既没有发生循环引用,那么走到这里的对象已经是代理对象了,不会再去三级缓存中找
//如果二级缓存不为空,说明在初始化的时候已经由于其他Bean的初始化调用了三级缓存中的函数,既发生了循环引用,那么这里使用二级缓存中的对象替换当前对象
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
...
}
}
}
...
return exposedObject;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
此时一级缓存三级缓存没有这个实例,二级缓存中有。
再回过头来看看getSingleton方法
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//加锁后重新从一级缓存中获取一遍,确保单例
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
...
try {
//调用这个封装了Bean创建流程的函数
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch ...
if (newSingleton) {
//添加到一级缓存,清除二级缓存和三级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
到此,三级缓存的流程结束。Bean从三级缓存到二级缓存最后存放到一级缓存,也就是单例池中。
# 循环引用
简单举例就是:
@Servie
public class A {
@Autowired
private B b;
}
@Servie
public class B {
@Autowired
private A a;
}
2
3
4
5
6
7
8
9
10
假设没有三级缓存,只有一个单例池用于存放创建好的Bean
按照上文提到的Bean创建流程,先通过反射调用构造函数创建A实例,然后初始化A,自动注入B,getBean获取B,发现B不在单例池中,那么进入B的创建流程
通过反射调用构造函数创建B实例,然后初始化B,自动注入A,getBean获取A,发现A不在单例池中,那么进入A的创建流程
由于A与B的相互引用,导致spring在创建Bean的时候陷入死循环。
为了解决这个问题,spring引入了三级缓存,通过早期暴露出只是实例化还未初始化的Bean,来解决死循环问题。
这样,在最开始创建完A后,暴露到三级缓存中,在进入B的创建流程后,B初始化注入A时就可以从三级缓存中获取到。
这样一看,似乎只需要两个缓存也可以解决循环引用问题,那么Spring为什么要用三个缓存呢?
这要从第三级缓存singletonFactories的作用说起。
从上文源码中可以知道三级缓存存放的实际上是一个获取早期Bean的函数
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
2
3
4
5
6
7
8
9
10
11
12
实际上,从上文可以知道早期Bean并不是在这个方法里创建的,这个方法只是对刚实例化的Bean进行一些后置处理。其中拿AOP举例,经过后置处理后返回的其实是代理对象。
所以第三级缓存的作用也就是允许执行一些后置处理,得到一个不是原对象的代理对象。
同时,三级缓存中的函数只能执行一次,不然多次调用,产生多个代理,必然违反单例原则,所以三级缓存中的函数执行完会立即放到二级缓存中。
那么我们可能会想,在一开始实例化A后,就直接进行后置处理,得到代理对象存放在二级缓存中,这样就不需要第三级缓存了,这样确实可以,但是并不是所有的Bean都存在循环引用的问题,这样处理,所有的Bean都会在构造完成后就生成代理对象,这违背了Spring的设计原则。而使用三级缓存,只针对真的发生了循环引用的Bean提前暴露代理对象,显得稍微优雅一些。