springboot ApplicationContext之finishBeanFactoryInitialization(getBean(),循环依赖)上

定义了以下两个bean(单例),看看spring是怎么生产出来提供给我们用的。

@Service
public class TestA {

    @Autowired
    private TestB testB;
}

@Service
public class TestB {

    @Autowired
    private TestA testA;
}

这个大家一看就知道怎么回事,我想要讲的是什么。循环依赖么,看上去是怎么也绕不开的话题,平常开发中会在不经意之间就使用上了,我们就从这里出发看看,spring是怎么解决的,但是重点是要了解bean的实例化、初始化流程。

还是比较喜欢图,因为比文字短,且看的清楚。
![bean的获取流程](https://img-blog.csdnimg.cn/d578acbd94e24d2a82ab6233c8810e20.png
getSignleton方法的流程
图虽然清晰但是也要加文字的,不然也不能说的很清楚。

图一中绿色加数字的是执行的方法,并按照数字从小到大顺序执行,箭头对应的方块是重要的参数,注意本文撇去了Aop相关的步骤。

TestA,获取流程:

  1. getBean,获取bean入口
  2. doGetBean
  3. getSingleton,重要方法(解决循环依赖),这个时候会执行到①,会去一级缓存(singletonObjects)获取为null,但是isSingletonCurrentlyInCreation(beanName)的方法为false,没有在创建中,返回是null.
  4. markBeanAsCreated,标记当前bean在创建中
  5. getSingleton,注意这个方法跟3不是同一个,参数不一样,重要参数singletonFactory
	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;
		}
	});
	5.1.1 beforeSingletonCreationation,标记为TestA创建中
	5.1.2 singletonFactory.getObject(),或执行传入的代码
  1. createBean,开始创建bean

  2. resolveBeforeInstantiation,实例化前的操作,先忽略

  3. doCreateBean

  4. createBeanInstance,实例化一个TestA。《springboot启动bean加载处理器ConfigurationClassPostProcessor 四(@bean注解)

       a:  instantiateUsingFactoryMethod 工厂方式创建bean(之前在@bean注解中介绍过)
       b:  instantiateBean
    
  5. addSingletonFactory, 向三级缓存对象singletonFactories,放入一个ObjectFactory<?> singletonFactory,对应的key=TestA

       addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))
    

11.populateBean, 这个时候如果不存在循环依赖,用不到三级缓存(三级缓存是存在TestA,但是用不到),会直接继续完成初始化

	TestA                                           TestB
	--------------------------------------------------------------
	populateBean(A)       
	-------------------------------------------------------------
	                                                getBean(B)
	                                                 ...
	                                                populateBean(B)     
	--------------------------------------------------------------
	getBean(A)
	getSingleton(A)
	-------------------------------------------------------------
		                                             initializeBean(B)
		                                                 B完成实例化
    -------------------------------------------------------------
	initializeBean(A)
	
	赋值TestA的属性TestB,这个时候会重新到(方法:1)开始执行,一直执行到TestB的 populateBean,
	需要赋值TestA,又回到(方法:1),执行到(方法:3),这个时候会执行到getSingleton ③,
	获取到TestA的singletonFactory返回的bean,放入到二级缓存earlySingletonObjects,
	并从三级缓存中移除,返回对象TestA(未初始化)。这个时候 TestB会对A进行赋值,并完成初始化。
  1. initializeBean,实例化TestA
  2. invokeAwareMethods
  3. invokeInitMethods
  4. addSingleton, 把TestA放入到一级缓存singletonObjects中,并冲二级缓存中移除

看看整个过程中,一、二、三级缓存的动态吧。
在这里插入图片描述
总结来说,spring解决循环依赖的处理是,把bean的实例化、初始化分开所以如果bean是构造注入的,那怎么也玩不转了

接下来就是,搜索一大把问题,

spring可以不要三级缓存吗?,看上去是可以的吧,只要两个缓存就可以了,把TestA创建好后直接放入到二级缓存,TestB要的时候直接拿。
看看我后续的解释吧。。。《springboot ApplicationContext之finishBeanFactoryInitialization(getBean())下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值