Spring 加载过程学习
启动:AbstractApplicationContext
obtainFreshBeanFactory():加载bean信息。主要是通过DefaultListableBeanFactory来加载。
obtainFreshBeanFactory()里面通过loadBeanDefinitions()加载bean信息时,这里多个子类分别对应xml和注解扫描.然后组装成BeanDefintion放到BeanFactory里。
finishBeanFactoryInitialization():进行bean的实例化,创建单例,解析@Autowiered注解等。
其中实例化时getSingleton()这里就是设置三级缓存,并获取bean(这就是Spring允许循环依赖的原因)。最后放进beanFactroy.
三级缓存获取过程:(singletonObjects,earlySingletonObjects,singletonFactories)
1.判断一级是否存在,一级缓存里bean为空并且bean在正在创建过程中才会从二级缓存中获取。否则返回空。如果从二级缓存获取还是空,则从三级缓存里获取,并把它放入二级缓存。然后在从三级缓存里移除。
2.判断从三级缓存里都取不到bean A,开始A的实例化,实例化完成后加入第三级缓存(singletonFactories放的是实例化的这个类。)实例化后开始初始化(处理A类属性,比如A类依赖B类),从bean工产里面获取类b,此时b的类还没有创建的话,则需要创建这个类,重复上面流程,把B也放入第三级缓存singletonFactories。此时A和B都被实例化,但是都还没有初始化。
3.如果B也依赖A,那么在B实例化时,重复上面流程,B的初始化首先从一级里面取A,没有,但是A正在创建过程中,所以此时从二级里面取,二级里面没有。所以从三级里面取到A,然后并把A放入二级缓存。然后在从三级缓存里移除A.
4.此时B完成了初始化,把b放入一级缓存,a还在初始化过程。然后重复上面流程。此时B已存在,所以A可以初始化完成。同样把a放入一级,然后再从二级里移除。
从上面流程可以看出,解决循环依赖的关键是实例化和初始化分开的(实例化时就就放入三级缓存。)。如果A里面把B定义成静态的,那么A在实例化时就必须获取到B,而此时B还没创建,创建B的时候又依赖A,然而A还在实例化,三级缓存里面还没有A,所以b初始化失败,报找不到A类。
为什么使用三级缓存呢?
1.只有一级缓存的话,里面会存在很多实例化但未初始化的数据,多线程环境下都从一级缓存取,这样会导致很多依赖数据为空。
2.二级缓存可以解决循环依赖问题,三级缓存的意义?
解决代理类的问题。如果只有二级(一级二级里面放的都是object,三级放的是FactoryObject),刚开始二级放的是实例好的对象,那么代理处理生成新的代理类的时候,重新放入二级。那么之前和之后,别人取到的类就不是同一个了。