什么是IOC:
IOC就是(Inversion of Control) 俗称 控制反转
IOC是一种思想,是可以帮我们管理对象,不用我们管理bean之间的耦合关系,也不用管对象是怎么实例化初始化的
这里简单说一下spring加载bean的流程
首先是BeanDefinitionReader接口封装了一些加载读取Bean信息的方法,然后读取到这个信息以后封装成一堆BeanDefinition,然后加载放入BeanDefinitionRegistry的一个map中,BeanDefinitionRegistry向工厂注册这些bean信息,中间会经过一个BeanFatoryPostProcessors接口,可以实现这个接口对bean进行扩展
什么是循环依赖
依赖就是一个bean依赖了另一个bean
如下图:
A类中要注入B这个bean,而B类中要注入A这个bean,互相依赖我们就把它称之为循环依赖
那么spring是如何解决的循环依赖呢:
首先我们要明白什么是实例化什么是初始化
实例化:创建对象,此时对象还是一个空对象
初始化:为对象赋值填充属性
spring通过实例化和初始化分为两个步骤来解决循环依赖
不明白也没关系,下面就通过源码来具体看看spring是怎么实现的
通过源码看spring究竟是怎么实例化初始化bean并解决bean之间循环依赖关系的:
这里编译的是spring5.0的源码
首先在xml文件中让两个类去相互依赖
spring容器启动
调用了构造方法的refresh()方法
在倒数第二个方法 里面做了准备工作和实例化懒加载的单例bean
最后一个方法是实例化懒加载的单例bean
首先,spring加载bean大致分为4步,getBean,doGetBean,createBean,doCreateBean。
这里做完判断以后就会去getBean
进去以后就会看见方法doGetBean
点进去
会在单例池中get这个bean 也就是一级缓存
方法实现:
第一次get为空,并且没有被暴露,这里的暴露是指spring在实例话完成后判断如果支持循环依赖那么就会把这个bean放入三级缓存,这个操作称之为暴露bean
返回null
开始创建bean 调用这个方法 key是beanName value是一个lambda表达式 但并没有被执行
进来发现是先在一级缓存中get这个bean 如果为null 下边掉用了getObject才是调用了createBean
do开头的方法是做事情的方法 开始创建bean
这个方法用来实例化bean
进来以后spring会推断最合适的构造方法 我这个只是测试,调用了最简单的无惨构造
到这里以后就完成了bean的实例化
然后跳出来
到这里以后就会把这个bean放入到三级缓存中,这一步操作就是暴露了这个bean
这里传入的也是个lamda表达式 也是没有被执行
放入三级缓存:
然后开始初始化这个bean 进行依赖注入
发现有一个属性
然后开始
解析一些必要的属性值吧应该 我猜的
这是一个还没准备好的类型,暂时不太明白这个类型的意义
然后getBean 要给A的B属性装配
又到doGetBean方法 循环一次
单例池也是获取不到B 会创建一次B
在实例化B后会给B的A属性填充 会开始getBean 而A是已经暴露在了三级缓存中,A还是个半成品,但已经可以让B拿到然后初始化了
这个是getBean的逻辑 首先从一级缓存里拿,然后是二级三级
拿到这个bean B就完成了属性的依赖注入 然后开始初始化这个bean
先执行判断这个bean有没有实现aware接口 实现了就调用aware接口的属性填充方法
beanPostProcessors 的postProcessBeforeInitialization方法
执行initMethod方法 这个方法会判断是否实现了initializationBean接口 如果是就会先调用afterPropertiesSet方法 在调用initMethod
beanPostProcessors的postProcessAfterInitialization,大名顶顶的AOP就是这个接口实现的
然后B就完成了初始化
然后把B放到一级缓存中
然后A也能拿到B的bean
spring官网给出解决循环依赖的思路
总结一下:spring解决循环依赖主要是将实例化和初始化分开,实例化完成后加入到三级缓存中,使得依赖的bean可以get到他。
bean的实例化初始化过程就是首先先在单例池get这个Bean,调用doGetBean方法,如果没有,会开始创建Bean,doCreateBean,实例化完成后,开始属性的注入,如果依赖其他bean,流程一样,最后属性装配完成后,开始初始化,调用aware接口,beanPostProcessors的before方法,afterPropertySet方法, initMethod方法,beanPostProcessors的after方法,完成初始化
后续会继续加油!!!