一、Spring IOC是什么
- IOC:控制反转,是一种设计模式。
- 一层含义是控制权的转移,由传统的在程序中控制依赖转移到由容器来控制。
- 第二层是依赖注入:将相互依赖的对象分离,在Spring配置文件中描述他们的依赖关系,他们的依赖关系只在使用的时候才建立,简单来说就是不需要的NEW一个对象了。
控制反转是反转的什么?
1)传统模式:控制权在开发者手中。
2)IoC 模式:控制权从开发者转移到容器,开发者不再需要手动管理对象间的依赖。
二、流程介绍:
Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() ⽅法中
@Override
publicvoidrefresh()throwsBeansException,IllegalStateException{
synchronized(this.startupShutdownMonitor){
StartupStepcontextRefresh=this.applicationStartup.start("spring.context.refresh");
//刷新前的预处理
//Preparethiscontextforrefreshing.
prepareRefresh();
//BeanFactory创建流程一:获取BeanFactory;默认实现是DefaultListableBeanFactory
//加载BeanDefition 并注册到 BeanDefitionRegistry
//Tellthesubclasstorefreshtheinternalbeanfactory.
ConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();
//BeanFactory创建流程二:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
//Preparethebeanfactoryforuseinthiscontext.
prepareBeanFactory(beanFactory);
try{
//BeanFactory创建流程三:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
//Allowspost-processingofthebeanfactoryincontextsubclasses.
postProcessBeanFactory(beanFactory);
StartupStepbeanPostProcess=this.applicationStartup.start("spring.context.beans.post-process");
//BeanFactory创建流程四:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
//Invokefactoryprocessorsregisteredasbeansinthecontext.
invokeBeanFactoryPostProcessors(beanFactory);
//Bean创建流程一:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
//Registerbeanprocessorsthatinterceptbeancreation.
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//初始化资源、事件、监听流程一:初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
//Initializemessagesourceforthiscontext.
initMessageSource();
//初始化资源、事件、监听流程二:初始化事件派发器
//Initializeeventmulticasterforthiscontext.
initApplicationEventMulticaster();
//初始化资源、事件、监听流程三:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
//Initializeotherspecialbeansinspecificcontextsubclasses.
onRefresh();
//初始化资源、事件、监听流程四:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
//Checkforlistenerbeansandregisterthem.
registerListeners();
//Bean创建流程二:初始化所有剩下的⾮懒加载的单例bean
//Instantiateallremaining(non-lazy-init)singletons.
finishBeanFactoryInitialization(beanFactory);
//完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)
//Laststep:publishcorrespondingevent.
finishRefresh();
}
catch(BeansExceptionex){
if(logger.isWarnEnabled()){
logger.warn("Exceptionencounteredduringcontextinitialization-"+
"cancellingrefreshattempt:"+ex);
}
//Destroyalreadycreatedsingletonstoavoiddanglingresources.
destroyBeans();
//Reset'active'flag.
cancelRefresh(ex);
//Propagateexceptiontocaller.
throwex;
}
finally{
//ResetcommonintrospectioncachesinSpring'score,sincewe
//mightnoteverneedmetadataforsingletonbeansanymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
可以看到会有以下主流程:
主要有几大模块:
(1)执行前的预处理与执行后的context刷新
(2)BeanFactory创建流程
(3)Bean创建流程
(4)初始化资源、事件、监听流程
执行顺序如下:
(1)刷新前的预处理(配置环境参数、创建监听器、事件容器)
(2)BeanFactory创建流程一:获取BeanFactory(默认实现是DefaultListableBeanFactory) ,加载BeanDefition 并注册到 BeanDefitionRegistry
(3)BeanFactory创建流程二:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
(4)BeanFactory创建流程三:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
(5)BeanFactory创建流程四:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
(6)Bean创建流程一:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
(7)初始化资源、事件、监听流程一:初始化MessageSource组件(做国际化功能;消息绑定,消息解析)
(8)初始化资源、事件、监听流程二:初始化事件派发器
(9)初始化资源、事件、监听流程三:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
(10)初始化资源、事件、监听流程四:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
(11)Bean创建流程二:初始化所有剩下的⾮懒加载的单例bean
(12)完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)
三、BeanFactory创建流程
1.获取BeanFactory
时序图如下:
2.BeanDefinition加载解析及注册
主要有以下几步:
(1)Resource定位:指对BeanDefinition的资源定位过程。通俗讲就是找到定义Javabean信息的XML⽂件,并将其封装成Resource对象。
过程:
⼦流程⼊⼝在 AbstractRefreshableApplicationContext#refreshBeanFactory ⽅法中
依次调⽤多个类的 loadBeanDefinitions ⽅法 —> AbstractXmlApplicationContext —>AbstractBeanDefinitionReader —> XmlBeanDefinitionReader ⼀直执⾏到XmlBeanDefinitionReader 的doLoadBeanDefinitions ⽅法
doLoadBeanDefinitions()方法主要内容是:读取xml,将xml中的信息保存到Document对象,并解析document对象,封装BeanDefinition对象并注册
(2)BeanDefinition载⼊ :把⽤户定义好的Javabean表示为IoC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition。
主要是XmlBeanDefinitionReader 类的 registerBeanDefinitions ⽅法(在上述doLoadBeanDefinitions()方法中)会最终调用到DefaultBeanDefinitionDocumentReader中的processBeanDefinition方法
bdHolder=delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);为解析成BeanDefintionHolder对象
(3)注册BeanDefinition到 IoC 容器
接着上述的DefaultBeanDefinitionDocumentReader中的processBeanDefinition方法
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());为完成注册操作
所谓的注册就是把封装的 XML 中定义的 Bean信息封装为BeanDefinition 对象之后放⼊⼀个Map中,BeanFactory 是以 Map 的结构组织这些 BeanDefinition的。
四、Bean创建流程
备注:
1.lazy-init 延迟加载机制
普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥第⼀次进⾏context.getBean() 时进⾏触发。
(1)对于被修饰为lazy-init的bean Spring 容器初始化阶段不会进⾏ init 并且依赖注⼊,当第⼀次进⾏getBean时候才进⾏初始化并依赖注⼊
(2)对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经初始化完成并缓存了起
2.Spring IoC循环依赖问题
循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。
Spring中循环依赖场景有:
- 构造器的循环依赖(构造器注⼊)
- Field 属性的循环依赖(set注⼊)
循环依赖无法处理的情况
- 单例 bean 构造器参数循环依赖(⽆法解决)
- prototype 原型 bean循环依赖(⽆法解决)
Spring中解决循环依赖的过程
(1)BeanA对象在实例化之后立马放入三级缓存
(2)BeanB在创建过程中发现依赖A,那么去三级缓存使用尚未成型的BeanA
(3)将BeanA升级放到二级缓存
(4)BeanB创建完成之后会放入一级缓存
(5)BeanA使用一级缓存中的BeanB
备注:
(1)singletonObjects:一级缓存,存储的是所有创建好了的单例Bean。(解决AOP)
(2)earlySingletonObjects:二级缓存,完成实例化,但是还未进行属性注入及初始化的对象(解决对象完整性)
(3)singletonFactories:三级缓存,暴露的一个单例工厂,二级缓存中存储的就是从这个工厂中获取到的对象。(解决循环依赖)
更多内容:
Spring篇(1)--SpringBoot是什么?原理是怎么样的?
Spring篇(4-1)--Spring Bean 是什么及其生命周期阶段