手写 Spring 14 - 循环引用及三级缓存
z 2024-05-31
源码分析
Java
# 解析
在 getBean 创建过程中,最重要的大三步为:实例化、属性填充、初始化。
从流程可以看到,循环依赖主要发生在第二步(populateBean),也就是field属性注入的处理。
# 三级缓存及循环引用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
1
2
3
2
3
处理循环引用的关键点:
- 循环依赖的核心功能实现主要包括 DefaultSingletonBeanRegistry 提供三级缓存:
singletonObjects 、 earlySingletonObjects 、singletonFactories
,分别存放成品对象、半成品对象和工厂对象。同时包装三个缓存提供方法:getSingleton、registerSingleton、addSingletonFactory,这样使用方就可以分别在不同时间段存放和获取对应的对象了。 - 在 AbstractAutowireCapableBeanFactory 的 doCreateBean 方法中,提供了关于提前暴露对象的操作,
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition,finalBean));
,以及后续获取对象和注册对象的操作,exposedObject = getSingleton(beanName); 、 registerSingleton(beanName, exposedObject);
,经过这样的处理就可以完成对复杂场景循环依赖的操作。 - 另外在 DefaultAdvisorAutoProxyCreator 提供的切面服务中,也需要实现接口 InstantiationAwareBeanPostProcessor 新增的 getEarlyBeanReference 方法,便于把依赖的切面对象也能存放到三级缓存中,处理对应的循环依赖。
# 定义一些职责和能力
ObjectFactory 提前暴露的三级缓存工厂对象,在运行时动态地获取对象的实例。
DefaultSingletonBeanRegistry 在原先一级缓存的基础上,添加二级和三级缓存,及相应的add方法,同时改造缓存获取 bean 逻辑为优先一其次二最后三中查找。
InstantiationAwareBeanPostProcessor 接口添加 getEarlyBeanReference 方法。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { /** * 在 Bean 实例化之后初始化之前,获取 Bean 的早期引用并进行操作。 * 若不需要执行AOP的逻辑,直接返回Bean。 * * @param bean bean * @param beanName bean 名称 * @return {@link Object} */ default Object getEarlyBeanReference(Object bean, String beanName) { return bean; } }
1
2
3
4
5
6
7
8
9
10
11
12
13主要用于将 aop 对象也提前暴露到三级缓存中。在 DefaultAdvisorAutoProxyCreator 实现它返回 aop 代理对象。
# 具体的实现
- ObjectFactory
public interface ObjectFactory<T> {
/**
* 这个方法返回一个类型为 T 的对象实例,您可以通过调用 getObject 方法来获取。
* ObjectFactory 通常用于将对象的创建和初始化推迟到需要的时候,以避免在应用程序启动时立即创建所有对象。
* <p>
* 在 Spring 中,ObjectFactory 的一个常见用法是在解决循环依赖问题时。
* 当 Spring 需要创建一个 Bean,但该 Bean 正在创建中,因此还不能完全初始化时,它会将该 Bean 的 ObjectFactory 放入二级缓存(earlySingletonObjects)中,
* 以便其他 Bean 可以提前获取 Bean 的引用,而不会导致循环依赖问题。
* <p>
* 另一个常见的用例是在配置中声明原型(prototype)作用域的 Bean,因为原型作用域的 Bean 不会在容器初始化时立即创建,而是在每次请求时动态创建。
* 在这种情况下,ObjectFactory 可以用于获取原型作用域 Bean 的实例。
*
* @return {@link T}
*/
T getObject();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- DefaultSingletonBeanRegistry
/**
* 保存了所有单例 bean 和待销毁的 bean
*
* @author zhangpengjun
* @date 2023/3/15
*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
/**
* 空单例对象的内部标记,用作 ConcurrentHashMap(不支持null值)的标记值。
*/
protected static final Object NULL_OBJECT = new Object();
/**
* 一级缓存,一级缓存存储已经完全创建和初始化的单例 Bean 的实例。
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 二级缓存,用于存储正在创建中的 Bean 的实例(属性尚未填填充)。
* 当 Spring 创建 Bean 时,如果发现该 Bean 存在循环依赖,它会将 Bean 的实例放入这个缓存中。这个实例可以被其他 Bean 提前获取,以解决循环依赖问题。
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
* 三级缓存,存储的是 Bean 的工厂对象(ObjectFactory)。
* 当 Spring 创建 Bean 时,如果发现该 Bean 存在循环依赖,它会将 Bean 的工厂对象放入这个缓存中。这个工厂对象用于在后续创建 Bean 的过程中获取 Bean 的实例。
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
private final Map<String, DisposableBean> disposableBeans = new HashMap<>();
@Override
public Object getSingleton(String beanName) {
// 先从一级缓存获取
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null) {
// 再从二级缓存获取
singletonObject = earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 最后从三级缓存获取
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 三级缓存存在,放入二级缓存
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
}
@Override
public void registerSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
earlySingletonObjects.remove(beanName);
singletonFactories.remove(beanName);
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> objectFactory) {
if (!singletonFactories.containsKey(beanName)) {
singletonFactories.put(beanName, objectFactory);
earlySingletonObjects.remove(beanName);
}
}
@Override
public void registerDisposableBean(String beanName, DisposableBean bean) {
disposableBeans.put(beanName, bean);
}
@Override
public void destroySingletons() {
Set<String> keySet = disposableBeans.keySet();
Object[] disposableBeanNames = keySet.toArray();
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
Object beanName = disposableBeanNames[i];
DisposableBean disposableBean = disposableBeans.remove(beanName);
try {
disposableBean.destroy();
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
throw new BeansException("Failed to bean:[" + beanName + "] destroy", e);
}
}
}
}
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
- DefaultAdvisorAutoProxyCreator
* DefaultAdvisorAutoProxyCreator 是 Spring Framework 中的一个类,负责根据配置的 Advisors 自动为 Bean 创建代理。
* 它会扫描 bean,查找任何配置的 Advisors,并在必要时为这些 bean 创建动态代理。
* 在 Spring Framework 中,Advisors 是定义 advice 的对象,例如拦截方法调用额外的行为。
* <br/>
* 它的工作原理如下:
* <br/>
* 1. DefaultAdvisorAutoProxyCreator 在初始化阶段检查应用上下文中的所有 bean。
* 2. 它查找配置了 Advisors 的 bean。一个 Advisor 通常由切面逻辑(advice)和切入点(pointcut)组成,切入点用于指定 advice 应该应用的位置。
* 3. 对于每个配置了 Advisors 的 bean,DefaultAdvisorAutoProxyCreator 创建一个代理对象,该代理对象包装了原始的 bean。
* 4. 代理对象拦截对 bean 的方法调用,并应用配置的 Advisors 定义的 advice。
* 5. 当应用上下文中的其他 bean 请求原始 bean 时,它们将接收代理对象而不是原始对象。
*
* @author zhangpengjun
* @date 2023/4/19
*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private DefaultListableBeanFactory beanFactory;
private final Set<String> earlyProxyReferences = Collections.synchronizedSet(new HashSet<>());
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) {
return pvs;
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
private boolean isInfrastructureClass(Class<?> beanClass) {
return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (!earlyProxyReferences.contains(beanName)) {
return wrapIfNecessary(bean, beanName);
}
return wrapIfNecessary(bean, beanName);
}
private Object wrapIfNecessary(Object bean, String beanName) {
if (isInfrastructureClass(bean.getClass())) {
return bean;
}
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
// 不匹配当前类,过滤
ClassFilter classFilter = advisor.getPointcut().getClassFilter();
if (classFilter != null && !classFilter.matches(bean.getClass())) {
continue;
}
// 转换为代理对象返回
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTargetSource(new TargetSource(bean));
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setProxyTargetClass(false); // 默认使用 jdk 代理
return new ProxyFactory(advisedSupport).getProxy();
}
return bean;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
earlyProxyReferences.add(beanName);
return wrapIfNecessary(bean, beanName);
}
}
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# 将实现加入原有的逻辑中
- 修改
AbstractAutowireCapableBeanFactory#createBean
,在实例化之后,填充属性之前,”提前暴露“原始对象的引用(放入三级缓存),用于解决循环依赖。
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {
Object bean = null;
try {
// 判断是否返回 代理 Bean 对象(注释原因,改用 BeanPostProcessor#postProcessAfterInitialization() 实现)
// bean = resolveBeforeInstantiation(beanName, beanDefinition);
// if (bean != null) {
// return bean;
// }
// 实例化
bean = createBeanInstance(beanName, beanDefinition, args);
// 处理循环依赖,将实例化后的 bean 提前放入缓存中暴露出来
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
// ”提前暴露“原始对象的引用,用于解决循环依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
}
// 实例化后判断,对于不需要填充属性的 bean 直接返回
boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
if (!continueWithPropertyPopulation) {
return bean;
}
// 在设置 Bean 属性之前,允许 BeanPostProcessor 修改属性值(解析@Value @Autowired等)
applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
// 属性填充
applyPropertyValues(beanName, bean, beanDefinition);
// 添加 Bean 的初始化扩展
bean = initializeBean(beanName, bean, beanDefinition);
} catch (Exception e) {
throw new BeansException("Failed to bean:[" + beanName + "] instance", e);
}
// 添加单例 Bean 缓存
if (beanDefinition.isSingleton()) {
// 注册实现了 DisposableBean 接口的 单例Bean 对象,留待容器停止的时候调用。
registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
registerSingleton(beanName, bean);
}
return bean;
}
private Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
Object exposedObject = bean;
for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
exposedObject = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
return exposedObject;
}
private boolean applyBeanPostProcessorsAfterInstantiation(String beanName, Object bean) {
boolean continueWithPropertyPopulation = true;
for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor instantiationAwareBeanPostProcessor = (InstantiationAwareBeanPostProcessor) beanPostProcessor;
if (!instantiationAwareBeanPostProcessor.postProcessAfterInstantiation(bean, beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
return continueWithPropertyPopulation;
}
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
59
60
61
62
63
64
65
66
67
68
69
70
# 测试
- xml 准备,spring-cyclic-dependence.xml。
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<!-- 目标类 -->
<bean class="com.snail.springframework.cyclicDependence.A">
<property name="b" ref="b"></property>
</bean>
<bean class="com.snail.springframework.cyclicDependence.B">
<property name="a" ref="a"></property>
<property name="c" ref="cFace"></property>
</bean>
<bean id="cFace" class="com.snail.springframework.cyclicDependence.CFace"></bean>
<!-- aop -->
<bean class="com.snail.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<!-- 切面逻辑 -->
<bean id="bAdvice" class="com.snail.springframework.cyclicDependence.BAdvice"></bean>
<bean id="methodInterceptor" class="com.snail.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor">
<property name="methodBeforeAdvice" ref="bAdvice"/>
</bean>
<!-- 切入点 -->
<bean class="com.snail.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="methodInterceptor"></property>
<!-- cglib 代理 -->
<property name="expression" value="execution(* com.snail.springframework.cyclicDependence.IFace.*(..))"></property>
</bean>
</beans>
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
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
- 提前准备,A(循环引用类)、B(循环引用类)、BAdvice(B切面)、IFace接口、CFace(接口实现类)
public class A {
private B b;
public String print() {
return "A print b: " + b;
}
}
public class B {
private A a;
private IFace c;
public String print() {
return "B print a: " + a + "\n\t\tB print Face c: " + c.getFace();
}
}
public class BAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("BAdvice before method: " + method);
}
}
public interface IFace {
String getFace();
}
public class CFace implements FactoryBean<IFace> {
@Override
public IFace getObject() {
return (IFace) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IFace.class}, ((proxy, method, args) ->
"proxy face method name: " + method.getName()
));
}
@Override
public Class<?> getObjectType() {
return IFace.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
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
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
- 测试类
public class SpringCyclicDependenceTest {
/**
* 测试三级缓存循环引用
*/
@Test
public void test_cyclic_dependence() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring-cyclic-dependence.xml");
A a = applicationContext.getBean(A.class);
System.out.println("测试结果:" + a.print());
B b = applicationContext.getBean(B.class);
System.out.println("测试结果:" + b.print());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 测试结果
测试结果:A print b: com.snail.springframework.cyclicDependence.B$$EnhancerByCGLIB$$d03a45b9@37374a5e
测试结果:B print a: com.snail.springframework.cyclicDependence.A$$EnhancerByCGLIB$$c473690e@4671e53b
B print Face c: proxy face method name: getFace
1
2
3
2
3
# 总结
以上面A
、B
类使用属性field
注入循环依赖的例子为例,对整个流程做文字步骤总结如下:
- 使用
context.getBean(A.class)
,旨在获取容器内的单例A(若A不存在,就会走A这个Bean的创建流程),显然初次获取A是不存在的,因此走A的创建之路~ 实例化
A(注意此处仅仅是实例化),并将它放进缓存
(此时A已经实例化完成,已经可以被引用了)初始化
A:@Autowired
依赖注入B(此时需要去容器内获取B)- 为了完成依赖注入B,会通过
getBean(B)
去容器内找B。但此时B在容器内不存在,就走向B的创建之路~ 实例化
B,并将其放入缓存。(此时B也能够被引用了)初始化
B,@Autowired
依赖注入A(此时需要去容器内获取A)此处重要
:初始化B时会调用getBean(A)
去容器内找到A,上面我们已经说过了此时候因为A已经实例化完成了并且放进了缓存里,所以这个时候去看缓存里是已经存在A的引用了的,所以getBean(A)
能够正常返回- B初始化成功(此时已经注入A成功了,已成功持有A的引用了),return(注意此处return相当于是返回最上面的
getBean(B)
这句代码,回到了初始化A的流程中~)。 - 因为B实例已经成功返回了,因此最终A也初始化成功
- 到此,B持有的已经是初始化完成的A,A持有的也是初始化完成的B,完美~
打赏一下
「真诚赞赏,手留余香」
# 打赏记录
打赏者 | 打助金额 (元) | 支付方式 | 时间 | 备注 |
---|---|---|---|---|
John | 12 | 微信 | 2020-06-09 | tip of you |
艾斯 | 32 | 支付宝 | 2020-07-11 | 火拳赞赏 |
HickSalmon | 15 | 微信 | 2020-09-21 | 有赏交流 |