循环依赖
产生原因
在bean的生命周期过程当中,在进行属性填充的时候,如果A依赖B,而且B也依赖A,去单例池获取依赖的对象的时候获取不到所依赖的对象则会创建新的对象<br>那么这种情况会循环创建
解决思路
就是循环依赖产生的时候有一个中间的缓存,存入未完全初始化完的对象,那么初始化B的时候发现依赖A,创建A的时候去这个缓存当中找一下有没有A,如果有A则终止循环依赖
基于上面思路产生的问题
二级缓存只是存入的未完全初始化的对象,如果这个对象需要AOP代理,而AOP代理则是在生命周期的初始化后,那么产生的这个对象则会不一致<br>产生上面的情形可以有一个解决思路,就是在B创建的时候,先创建A,A如果有代理,则先创建代理再放入二级缓存,但是这样的话没有经过后面的完整生<br>生命周期
如何判断出现了循环依赖?
A依赖B,B也依赖A;当创建A的时候先记录正在创建中的Bean为A,当创建A当中的B的时候再去创建A的时候比较一下当前的创建Bean是不是A,是就出现了循环依赖
spring容器中重要的三级缓存
一级缓存:singletonObjects<br>保存经过完整生命周期的bean
二级缓存:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整生命周期的bean。<br>还有一种情况就是:如果A依赖B和C,在创建B的时候如果A已经放入earlySingletonObjects里面了,这个时候创建的时候是不需要再创建A的不需要再一次经过AOP,应为创建B已经AOP了,保证单例
三级缓存:缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖(当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))
思考:怎样去spring容器当中拿一个bean?<br>先去一级缓存拿,再去二级缓存,最会再去三级缓存拿
回顾bean的产生过程
spring扫描得到BeanDefinetion
根据BeanDefinetion生成Bean对象
根据推断出来的构造方法得到一个原始对象
填充属性,也叫作依赖注入
填充属性基本逻辑:先去单例池里面找有没有,如果没有则会创建
如果某个方法被AOP会生成代理对象
将代理对象放入单例池
bean的生命周期当中实例化的时候会调用doCreatBean方法
执行 applyMergedBeanDefinitionPostProcessors
postProcessMergedBeanDefinition
AutowiredAnnotationBeanPostPreoccer.postProcessMergedBeanDefinition
寻找@Autowired的属性
寻找@Autowired的方法
属性填充populateBean<br>
AutowiredAnnotationBeanPostProcessor..postProcessProperties()<br>
初始化 initializeBean
注册销毁的逻辑
属性填充
AutowiredAnnotationBeanPostProcessor..postProcessProperties()
findAutowiringMetadata
buildAutowiringMetadata<br>
填充属性上带有@Autowired的注解的属性
AutowiredFieldElement.inject
填充方法上带有@Autowired的注解的方法
AutowiredMethodElement.inject
CommonAnnotationBeanPostProcessor.postProcessProperties()<br>
SourceElement.inject
解决循环依赖
创建bean的时候也就是doCreatBean的时候会进行判断,如果是单例并且正在创建先将B的ObjectFactory加入三级缓存<br>
属性赋值获取bean的时候会去三级缓存拿,能够拿到那的是一个lamd表达式,里面会执行getObjecy然后执行wrapIfNecess,里面会进行判断如果有AOP则产生的是代理对象,如果没有AOP则产生原始对象
AOP动态代理的时候会通过AbstractAutoProxyCreator产生动态代理,会wrapIfNecess,也是判断是否有AOP,有就动态代理,没有则返回原始对象<br>
spring的整合
整合myBaties:整合原理,将Dao层的接口注入到spring当中交给spring管理,<br>并且通过@Autowired注解能够注入代理对象<br>
前置知识点
FactoryBean的调用时机
getBean
doCreatBean
判断单例、原型、是不是有父类FactoryBean等
getObjectForBeanInstance<br>
super.getObjectForBeanInstance<br>
getObjectFromFactoryBean
doGetObjectFromFactoryBean
FactoryBean.getObject();
整合过程
扫描获取所有的接口类,并且将所有扫描出来的bean转换成FactoryBean
新增myBaties扫描注解@MapperScan,申明扫描路径
@MapperScan增加ImportBeanDefinetionRegisterPostProcessor<br>
MapperScanRegister<br>
实现了ImportBeanDefinetionRegisterPostProcessor
执行ImportBeanDefinetionRegisterPostProcessor.registerBeanDefinitions<br>
获取扫描路径:AnnotationMetadata。getAllAnnotationAttributes。get("path")<br>
开启扫描逻辑 //自定义扫描起继承自ClassPathMapperScanner,<br>重写doScan和增加addExcludeFilter为匹配所有的类为true<br>
扫描到所有beanDefinetion以后修改beaName为FactoryBean和添加对应的构造方法赋值<br>
容器遍历所有的BeanDefinetion进行属性赋值的时候会进行判断,<br>如果是Factorybean则最终会调用FactoryBean.getObject方法生成jdk动态代理对象<br>
FactoryBean.getObject
SqlSession.getMapper
jdk动态代理
Proxy.newProxyInstance(ClassLoader,XXX.class,InvocationHandler)
执行动态代理的方法
getMapgger
SessionFactory.Opensession
session.selectOne
配置文件解析
sql执行