首先明确,Spring-webmvc基于Servlet-Api标准,应用上下文(WebApplicationContext)初始化的入口也是基于Servlet-Api标准。
在spring-webmvc中初始化一个WebApplicationContext有几种方式:
1.通过实现WebApplicationInitializer
2.继承AbstractDispatcherServletInitializer(WebApplicationInitializer的实现类)
3.通过web.xml(部署描述符文件)配置ContextLoaderListener,指定配置文件或配置类
4.配置DispatcherServlet时,指定其应用上下文的配置文件或配置类
其更底层是基于以下两种Servlet标准:
1.使用ServletContextListener,通常是加载全局级别的WebApplicationContext,最终会在ContextLoader的initWebApplicationContext方法中初始化应用上下文
2.使用ServletContainerInitializer,通过ServletContext添加DispatcherServlet,设置应用上下文的配置文件或配置类。用于加载Servlet级别的WebApplicationContext,最终会在FrameworkServlet的initServletBean方法中初始化应用上下文
一、web应用上下文(WebApplicationContext)初始化的入口
1.使用ServletContextListener的方式初始化WebApplicationContext
首先需要在web.xml中完成ContextLoaderListener
ContextLoaderListener继承ContextLoader类,并实现ServletContextListener接口,ServletContext初始化时会进入回调方法
然后来到ContextLoader.initWebApplicationContext方法中开始执行ApplicationContext的配置和刷新,关联ServletContext和ApplicationContext等工作
在webmvc中通常实例化的是XmlWebApplicationContext和AnnotationConfigWebApplicationContext这两种类型的ApplicationContext,后续将以XmlWebApplicationContext作为例子进行讨论
进入configureAndRefreshWebApplicationContext方法,完成web环境属性源的初始化,通过ApplicationContextInitializer对ApplicationContext进行定制,最后开始进行刷新容器(这里就是常规的Spring应用上下文刷新工作,后续讨论)
2.使用ServletContainerInitializer的方式初始化应用上下文
首先需要配置WebApplicationContext,这里通过继承AbstractAnnotationConfigDispatcherServletInitializer的方式,AbstractAnnotationConfigDispatcherServletInitializer中提供了三个抽象方法
(1)getRootConfigClasses()指定Root WebApplicationContext的配置类,通过ContextLoaderListener完成加载
(2)getServletConfigClasses()指定当前Serlvet的WebApplicationContext配置类,在DispatcherServlet初始化时完成加载
(3)getServletMappings()配置当前Servlet的映射路径
SpringServletContainerInitializer是初始化的入口,从这里调用所有WebApplicationInitializer的onStartup方法,这里我们使用的是AbstractAnnotationConfigDispatcherServletInitializer的子类,从继承体系中定位到AbstractDispatcherServletInitializer的onStartup方法
AbstractDispatcherServletInitializer先调用了父类(AbstractContextLoaderInitializer)的onStartup方法
在AbstractContextLoaderInitializer的onStartup方法中,如果能够拿到Root WebApplicationContext的配置类,就会注册一个ContextLoaderListener来加载Root WebApplicationContext,这里前面讨论的是一样的。
执行完父类的onStartup方法后,AbstractDispatcherServletInitializer执行registerDispatcherServlet,获取到Servlet WebApplicationContext配置类,创建并注册一个DispatcherServlet,最后注册所有的Filters
此时已经把配置了WebApplicationContext的DispatcherServlet注册到ServletContext中,实际还没有完成Servlet WebApplicationContext的加载。
接下来先是ServletContextListener会完成Root WebApplicationContext,然后每个DispatcherServlet在初始化时完成Servlet WebApplicationContext的加载
通过DispatcherServlet的继承体系结构定位到初始化方法执行的是HttpServletBean的init方法
接入进入FrameworkServlet的initServletBean方法,在这里执行initWebApplicationContext完成Servlet WebApplicationContext的加载
在initWebApplicationContext方法中
如果存在Root WebApplicationContext会将其关联到当前加载的WebApplicationContext上
如果当前Servlet未创建有WebApplicationContext,会尝试从ServletContext的属性中查找,找不到则创建一个。总之,这里会通过configureAndRefreshWebApplicationContext方法进入常规的Spring应用上下文刷新流程,完成Servlet WebApplicationContext的配置和刷新
然后进行FrameworkServlet的刷新配置,DispatcherServlet重写了onRefresh方法,执行其初始化策略,从WebApplicationContext中获取以下组件,完成关联
(1)文件解析器(MultipartResolver)
(2)本地化解析器(LocaleResolver)
(3)一组处理器映射(HandlerMapping)
(4)一组处理器适配器(HandlerAdapter)
(5)一组异常处理器(HandlerExceptionResolver)
(6)一组视图解析器(ViewResolver)
…
最后将WebApplicationContext关联到ServletContext上,完成初始化流程
二、web应用上下文的刷新
这里使用XmlWebApplicationContext作为例子讨论Web应用上下文的刷新,XmlWebApplicationContext继承自AbstractApplicationContext类,并没有重写其refresh方法,所以XmlWebApplicationContext走的还是AbstractApplicationContext的refresh方法,另外在XmlWebApplicationContext的继承体系中,AbstractRefreshableWebApplicationContext重写了两个钩子方法postProcessBeanFactory和onRefresh,以下是刷新流程概览
1.刷新准备工作
在AbstractApplicationContext.onRefresh中
首先进入prepareReshresh方法,激活容器,初始化并校验属性源
2.获取刷新好的BeanFactory
进入obtainFreshBeanFactory方法,refreshBeanFactory被持有DefaultListableBeanFactory对象的子类AbstractRefreshableApplicationContext重写,创建并配置新的BeanFactory后,开始加载BeanDefinition,XmlWebApplicationContext重写了loadBeanDefinitions方法(XmlWebApplicationContext并没有继承AbstractXmlApplicationContext,它重写loadBeanDefinitions和AbstractXmlApplicationContext是一样的)
加载BeanDefinition的细节暂不展开
3.BeanFactory的准备工作
进到prepareBeanFactory方法
设置Bean类加载器、Spel解析器、属性编辑器的注册器
添加Bean后置处理器ApplicationContextAwareProcessor,并设置忽略ApplicationContextAwareProcessor可以注入的XxxAware依赖接口
将当前BeanFactory注册为后续所有依赖类型为BeanFactory的依赖注入值
将当前ApplicationContext注册为后续所有依赖类型为ResourceLoader/ApplicationEventPublisher/ApplicationContext的依赖注入值
将环境对象、JVM系统属性对象、OS系统属性对象注册为容器单例对象
4.后置处理BeanFactory
进到postProcessBeanFactory,这个方法在AbstractApplicationContext中是空实现,在XmlWebApplicationContext的继承体系中由AbstractRefreshableWebApplicationContext提供了实现。
与ApplicationContext类似的,添加一个ServletContextAware后置处理器,忽略XxxAware接口。
5.执行BeanFactory的后置处理器(BeanFactoryPostProcessor)
BeanFactoryPostProcessor可以拿到ConfigurableListableBeanFactory,对其执行一些定制化操作,如果BeanFactory实现了BeanDefinitionRegistry接口,还可以实现BeanDefinitionRegistryPostProcessor手动注册BeanDefinition。这里实例化的BeanFactory是DefaultListableBeanFactory。
在invokeBeanFactoryPostProcessors方法中
(1)先执行当前ApplicationContext持有的一组BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry
(2)(3)(4)从BeanFactory中获取BeanDefinitionRegistryPostProcessor类型的Bean(确认需要处理才会实例化),按照PriorityOrdered -> Ordered -> non-Order的顺序依次执行完postProcessBeanDefinitionRegistry,直至不再有新的BeanDefinitionRegistryPostProcessor注册进来
(5)执行所有BeanDefinitionRegistryPostProcessor类型的postProcessBeanFactory方法,执行当前ApplicationContext持有的常规BeanFactoryPostProcessor类型的postProcessBeanFactory方法
(6)从BeanFactory中获取BeanFactoryPostProcessor类型的Bean(确认需要处理才会实例化),排除在(5)中作为BeanDefinitionRegistryPostProcessor处理过的
(7)(8)(9)按照PriorityOrdered -> Ordered -> non-Order的顺序依次执行postProcessBeanFactory
6.注册时Bean的后置处理器(BeanPostProcessor)
进到registerBeanPostProcessors方法中,AbstractApplicationContext将具体操作委托给PostProcessorRegistrationDelegate。
在PostProcessorRegistrationDelegate的registerBeanPostProcessors方法中
(1)从BeanFactory中获取到BeanPostProcessor类型的Bean(此时还未实例化)
(2)注册一个BeanPostProcessorChecker(用于日志输出的)
(3)如果是MergedBeanDefinitionPostProcessor类型,将其保存到集合中,后续需要通过重新注册来保证这些处理器在列表的后面
(4)(5)(6)按照PriorityOrdered -> Ordered -> non-Order的顺序依次实例化和注册BeanPostProcessor
(7)重新注册MergedBeanDefinitionPostProcessor类型的处理器
7.初始化消息源
进到initMessageSource方法,
(1)如果当前BeanFactory包含有BeanName为messageSource且类型为MessageSource的bean,从BeanFactory中实例化Bean并设置为当前ApplicationContext的messageSource,,如果该messageSource是HierarchicalMessageSource类型且当前ApplicationContext存在父类,则将父类的messageSource设置为该messageSource的parentMessageSource;
(2)如果当前BeanFactory没有包含BeanName为messageSource的bean,实例化一个DelegatingMessageSource,设置当前ApplicationContext父类的messageSource为该messageSource的parentMessageSource,注册DelegatingMessageSource到容器中的单例对象
8.初始化事件多播器
进到initApplicationEventMulticaster方法中
(1)如果当前BeanFactory包含有BeanName为applicationEventMulticaster且类型为ApplicationEventMulticaster的bean,从beanFactory实例化Bean并设置为当前ApplicationContext的applicationEventMulticaster
(2)如果没有,则实例化一个SimpleApplicationEventMulticaster,设置为当前ApplicationContext的applicationEventMulticaster,并注册SimpleApplicationEventMulticaster到容器中的单例对象
9.刷新
AbstractApplicationContext的onRefresh是空实现,XmlWebApplicationContext的继承体系中由AbstractRefreshableWebApplicationContext提供了实现。AbstractRefreshableWebApplicationContext仅是做了初始化主题源的,并将具体操作委托给UiApplicationContextUtils,具体内容暂不做展开
10.注册应用事件监听器
进到registerListeners方法
(1)注册当前ApplicationContext持有的一组ApplicationListener
(2)从BeanFactory里中获取ApplicationListener类型的Bean(未实例化)并注册
(3)当前已持有ApplicationEventMulticaster,可以发布早期事件
11.实例化剩下(非懒加载)的单例Bean
进到finishBeanFactoryInitialization方法
(1)如果BeanFactory中存在BeanName为conversionService且类型为ConversionService的bean,将其实例化并设置为当前BeanFactory的ConversionService
(2)如果BeanFactory中没有String解析器,将Environment中实现的resolvePlaceholders方法配置为当前BeanFactory的String解析器
(3)实例化LoadTimeWeaverAware
(4)冻结所有的BeanDefinition,不希望再有改变
(5)开始Bean实例化工作
当前的BeanFactory实例是DefaultListableBeanFactory类型,进到它的preInstantiateSingletons方法中
(1)通过BeanDefition进行判断,需要满足:非抽象类、单例、非懒加载
(2)判断当前实例化的是不是FactoryBean
(3)先实例化FactoryBean,BeanName为&+BeanName
(4)如果FactoryBean是SmartFactoryBean且isEagerInit返回true,直接开始实例化该FactoryBean提供的Bean
(5)常规Bean,直接开始实例化
(6)对于所有已实例化的单例Bean,如果实现了SmartInitializingSingleton接口,调用其afterSingletonsInstantiated方法
getBean方法中具体的实例化过程暂不展开
12.最后的刷新工作
进到finishRefresh方法,执行善后工作。
13.其它
在context刷新过程中,如果出现异常,会销毁已创建Bean然后关闭context,最后在finilly中重置缓存