OUZHANBO

对于我这种菜鸡来说,毕业等于失业

0%

Spring 三级缓存

Spring 三级缓存

源码分析

测试代码如下:

启动类

1
2
3
4
5
6
7
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(TradeApplication.class, args);
configurableApplicationContext.getBean("testClassA");
}
}

TestClassA

1
2
3
4
5
6
7
8
@Lazy
@Component
public class TestClassA {
@Transactional(rollbackFor = Exception.class)
public void test() {
System.out.println("testA");
}
}

TestClassB

1
2
3
4
5
6
7
@Lazy
@Component
public class TestClassB {

@Resource
private TestClassA testClassA;
}

这里都加上 @Lazy的原因是 springboot 原本启动时还会加载其他的内部的 bean,为了更好的测试分析,让 TestClassA 和 TestClassB 延迟加载,再通过 getBean 方法在第一次获取 TestClassA 对应的 bean 的时候再加载

通过 configurableApplicationContext.getBean("testClassA")的 getBean 一路调试进去,会来到 AbstractBeanFactory.doGetBean 这个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//省略其他代码
/**主要关注点 1**/
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} else {
if (mbd.isSingleton()) {
/**主要关注点 2**/
sharedInstance = getSingleton(beanName, () -> {
try {
/**主要关注点 3**/
return createBean(beanName, mbd, args);
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}

从关注点 1 Object sharedInstance = getSingleton(beanName) 进入到 DefaultSingletonBeanRegistry.getSingleton方法

1
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
//一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

//二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

//三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);



public Object getSingleton(String beanName) {
//第二个参数allowEarlyReference传入true
return getSingleton(beanName, true);
}


protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}

DefaultSingletonBeanRegistry.isSingletonCurrentlyInCreation的逻辑如下

1
2
3
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
  1. 判断一级缓存中是否存在该 bean,如果存在直接返回,如果不存在走第 2 步
  2. 判断二级缓存中是否存在该 bean 并且isSingletonCurrentlyInCreation(beanName)返回是否为 true(判断当前 bean 是否正在被创建),不满足条件返回 null

但是因为testClassA这个 bean 现在还没被创建,并且isSingletonCurrentlyInCreation(beanName)这个方法返回的是 false(为什么是 false 后面会提到),所以直接返回 null

因为上面找不到所以会跑到关注点 2,这里也是调用 DefaultSingletonBeanRegistry.getSingleton方法,但是实现的逻辑和上面的不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
//省略其他代码
synchronized (this.singletonObjects) {
//先从一级缓存获取bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
/**主要关注点 4**/
beforeSingletonCreation(beanName);
boolean newSingleton = false;
try {
/**主要关注点 5**/
singletonObject = singletonFactory.getObject();
newSingleton = true;
} finally {
/**主要关注点 6**/
afterSingletonCreation(beanName);
}
if (newSingleton) {
/**主要关注点 7**/
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}

DefaultSingletonBeanRegistry.beforeSingletonCreation 逻辑如下

1
2
3
4
5
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}

主要关注点 4 中的逻辑主要是将 beanName 加入到 singletonsCurrentlyInCreation 中(singletonsCurrentlyInCreation 是个 Set 集合,只有不存在的时候才可以将 beanName 添加进去),而 singletonsCurrentlyInCreation 就在前面 DefaultSingletonBeanRegistry.isSingletonCurrentlyInCreation 被用到,所以前面为什么返回的 false

前面还有this.inCreationCheckExclusions.contains(beanName)这个判断,从名字能猜到 inCreationCheckExclusions 里面存放的是那些不需要被检查是否正在创建中的 beanName,如果不需要被检查就不需要添加到 singletonsCurrentlyInCreation 中

关注点 5 singletonFactory.getObject()是个 lambda 表达式,真正的逻辑其实就是关注点 3 中的createBean(beanName, mbd, args),最终会调用到 AbstractAutowireCapableBeanFactory.doCreateBean

1
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
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
//省略部分代码
// Instantiate the bean.
/**关注点 8**/
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}


// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
/**关注点 9**/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// Initialize the bean instance.
/**主要关注点 10**/
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}

if (earlySingletonExposure) {
/**关注点 11**/
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
}
}
}

}

关注点 8 主要是对实例化一个 bean,没什么好说的,关注点 9 判断的就是 bean 是否是单例(mbd.isSingleton())并且允许循环依赖(this.allowCircularReferences)并且 bean 正在被创建(isSingletonCurrentlyInCreation(beanName),前面介绍过了),earlySingletonExposure 在这里为 true(前面两个条件一般情况下都是 true ,第三个条件根据前面的介绍也是为 true)

DefaultSingletonBeanRegistry.addSingletonFactory 逻辑如下

1
2
3
4
5
6
7
8
9
10
11
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
//将bean加入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}

earlySingletonExposure 为 true 说明 bean 可以提早暴露,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))就是将 bean 先放入三级缓存,不过留意到这里加入三级缓存的是一个 ObjectFactory (先记住后面会提到)

关注点 10 主要是初始化 bean,populateBean(beanName, mbd, instanceWrapper)依赖注入,exposedObject = initializeBean(beanName, exposedObject, mbd)初始化 bean ,在这个测试例子中 TestClassA 需要注入 TestClassB,尝试从缓存获取 TestClassB 对应的 bean,但是因为 TestClassB 对应的 bean 还未被创建,所以和 TestClassA 创建 bean 的过程一样创建 TestClassB 的 bean,按照前面的逻辑走到 populateBean(beanName, mbd, instanceWrapper) 这一步,发现 TestClassB 中需要依赖 TestClassA,这个时候就从缓存中获取 TestClassA 的 bean,就是关注点 1 中的Object sharedInstance = getSingleton(beanName)(留意 allowEarlyReference 为 true 才会从三级缓存中获取),在三级缓存中获取到 TestClassA 的 ObjectFactory,通过 singletonObject = singletonFactory.getObject() 获取到 TestClassA 的 bean,之后通过this.earlySingletonObjects.put(beanName, singletonObject)this.singletonFactories.remove(beanName)这两段代码将 TestClassA bean 放入到二级缓存,将 TestClassA 的 ObjectFactory 从三级缓存中移除

从上面的分析可以知道singletonObject = singletonFactory.getObject()这段获取 TestClassA 的 bean 其实调用的就是AbstractAutowireCapableBeanFactory.getEarlyBeanReference这个方法

1
2
3
4
5
6
7
8
9
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}

图片丢失

SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference逻辑如下

1
2
3
4
5
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
}

AbstractAutoProxyCreator.getEarlyBeanReference 逻辑如下

1
2
3
4
5
6
7
8
9
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
}

SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference返回的就是传进去的 bean,但是 AbstractAutoProxyCreator 重写了 getEarlyBeanReference ,它其实就是 Spring 的代理实现,返回 bean 的代理对象,传入的 bean 被存放在代理对象的 target 成员变量中(如果不懂的话可以去了解一下代理模式,了解一下静态代理和动态代理是如何实现的),我们这里 TestClassA 上用到声明式事务(@Transactional 注解),所以这里 TestClassA 对应的 bean 不能返回原来的 bean,而是被 AbstractAutoProxyCreator 处理后的代理对象(后面都以 ProxyTestClassA 命名代理类),最后将 ProxyTestClassA 的 bean 注入到 TestClassB 的 bean 中,到此 TestClassB 的 bean 基本已经初始化完成,之后就是回到关注点 6 和关注点 7

afterSingletonCreation(beanName)逻辑如下

1
2
3
4
5
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}

因为 TestClassB 的 bean 已经完成实例化和初始化,所以将 TestClassB 的 beanName 从标记正在创建中的 singletonsCurrentlyInCreation 集合中移除

addSingleton(beanName, singletonObject)的逻辑如下

1
2
3
4
5
6
7
8
9
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//将bean放入一级缓存
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}

addSingleton(beanName, singletonObject)就是将 TestClassB 的 bean 放入一级缓存,并且将 bean 从二级和三级缓存中移除

之后就是回到关注点 10 的 TestClassA 的 bean 初始化(注意 TestClassA 的 bean 其实还初始化完成,前面说的一堆实例化和初始化 TestClassB 的 bean 逻辑都是因为 TestClassA 的 bean 需要注入 TestClassB 的 bean 导致的),将 TestClassB 的 bean 注入 TestClassA 的 bean 中,这个对于 TestClasA 的 bean 的处理基本完成,但是和 TestClassB 的创建和初始化有点不同的是在关注点 11

关注点 11 的Object earlySingletonReference = getSingleton(beanName, false)(这里传入的 allowEarlyReference 就是为 false 最多只会从二级缓存获取),前面二级缓存中存入了 TestClassA 的代理类 ProxyTestClassA 的 bean,所以通过 beanName 获取到的就是 ProxyTestClassA 的 bean,所以最后返回就是 earlySingletonReference(指向 ProxyTestClassA 的 bean 并且里面 target 指向的被代理 TestClassA 的 bean 已经初始化完成),之后的逻辑就和 TestClassB 的一样了

是否一定要使用三级缓存