Spring容器启动流程

通过AbstractApplicationContext#refresh()提供了在加载完配置文件后的启动过程。以SpringBoot的Web环境来看启动过程(文末有spring容器的启动过程及区别)

1.prepareRefresh():由于在此时还没有加载servlet容器,所以servletContext=null,servletConfig=null,还没有进行初始化propertySource,添加了几个ApplicationListeners。

实际上没任何操作
添加了监听器

2.obtainFreshBeanFactory():创建BeanFactory,即DefaultListableBeanFactory

3.prepareBeanFactory():对DefaultListableBeanFactory进行属性填充。如:添加类加载器,添加BeanPostProcessor等等。

填充属性

4.postProcessBeanFactory():在上面prepareBeanFactory()公共的之后,提供子类的特殊处理,注册特殊的后处理器,此处为ServletWebServerApplicationContext的具体实现。

web容器的实现

5.invokeBeanFactoryPostProcessors():主要是扫描包,注册成BeanDefinition,对类配置的信息解析成BeanDefinition的属性。然后执行实现了BeanFactoryPostProcessor接口的bean的postProcessBeanFactory()方法。

对BeanFactoryPostProcessor进行分类

对于BeanDefinitionRegistryPostProcessor类型的BeanFactoryPostProcessor,执行postProcessBeanDefinitionRegistry

SharedMetadataReaderFactoryContextInitializer类型的实现
SharedMetadataReaderFactoryContextInitializer类型的实现
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory

ConfigurationWarningsApplicationContextInitializer类型的processor,检查包名是否异常

ConfigurationWarningsApplicationContextInitializer类型的实现

获取类型为BeanDefinitionRegistryPostProcessor并且是PriorityOrdered优先排序类型的beanDefinition

优先排序的

上面获取postProcessorNames的具体实现如下

获取优先排序的beanDefinition的过程
获取优先排序的beanDefinition的过程

调用刚获取到的currentRegistryProcessor列表中的bean的postProcessBeanDefinitionRegistry()方法

对优先排序的进行优先处理

获取到启动类

优先排序bean的逻辑

对启动类开始进行解析,包装成SourceClass,开始解析

获取到需要扫描的包信息,开始进行解析

解析是否有includeFilters,excludeFilters,lazyInit等属性,解析basePackage,basePackageClasses配置,如果没有,则根据启动类的包名获取,最终获得需要扫描的包。

对启动类的配置进行解析,以获得最终的需要扫描的包和类

解析包下所有beanDefinition,遍历并逐个解析。  如果实现了AnnotatedBeanDefinition接口,解析是否有lazy,Primary,DependsOn,Role,Description等注解并对beanDefinition进行相应属性设置。   检查是否在beanDefinitionMap中,如果不存在则将beanDefinition注册到beanDefinitionMap中。

将包下的类包装成beanDefinition,并解析类的配置

对获取到的包下的beanDefinition进行遍历处理。处理是否import,ImportResource,Bean注解,处理实现的接口。

处理完BeanDefinitionRegistryPostProcessor类型的bean之后,处理之前注册的处理器,前两个处理器没做任何处理,第三个处理器ConfigurationClassPostProcessor,对目前加载的所有的beanDefinition进行处理。如果是启动类,生成代理类并替换原来的beanClass

生成代理类

获取实现了BeanFactoryPostProcessor接口的类,去除了上面已经解析过的internalConfigurationAnnotationProcessor,根据是否排序进行分类,然后按照PriorityOrdered,Ordered,nonOrdered以此执行。

对实现了BeanFactoryPostProcessor接口的类按照优先级进行分类
按照排序逐个调用BeanFactoryPostProcessor的实现类

6.registerBeanPostProcessors():获取实现了BeanPostProcessor的bean,并根据是否实现order接口进行排序,并按顺序注册到beanPostProcessors中。

7.initMessageSource():

8.initApplicationEventMulticaster():注册事件广播器

9.onRefresh():获取ServletWebServerFactory(tomcatServletWebServerFactory),创建TomcatWebServer,然后initServletPropertySources

创建TomcatWebServer之后获取需要初始化的servlet,filter

对需要初始化的servlet,filter进行处理

将servlet添加到servletContext中

将filter添加到servletContext中

10.registerListeners():在事件广播器中注册监听器,注册监听器name,如果earlyApplicationEvents存在,则广播事件。

事件广播器中添加监听器

11.finishBeanFactoryInitialization():实例化bean

对还没有实例化的类逐个实例化

先进行实例化之前的操作,再实例化bean。

实例化之前的操作

如果有实现InstantiationAwareBeanPostProcessor, 则执行postProcessBeforeInstantiation

实例化之前的操作

根据实例化策略进行实例化(这里是cglib)包装成BeanWrapper

根据实例化策略(cglib)进行实例化

实例化之后执行后处理

实例化之后的处理

执行postProcessProperties

设置属性之前的处理以及设置属性

属性设置,在AutowiredAnnotationBeanPostProcessor中进行依赖注入

依赖注入

是否实现BeanNameAware,BeanClassLoaderAware,BeanFactoryAware等接口

init之前

执行自定义的init方法之前以及执行自定义的init方法

调用自定义的init方法,在InitDestroyAnnotationBeanPostProcessor中处理

执行自定义的init方法

如果实现了InitializingBean,执行afterPropertiesSet()方法

执行完init之后

然后执行init之后的方法

执行完afterPropertiesSet()之后

12.finishRefresh():主要做的事情是启动tomcat,并发布事件

启动tomcat

逐个listener去匹配事件

发布事件
执行事件监听器


以下为spring环境启动与web环境启动的相同和不同:

1.prepareRefresh():区别在于initPropertySources()的实现不同,spring上下文为AnnotationConfigApplicationContext,web上下文AnnotationConfigServletWebServerApplicationContext

2.obtainFreshBeanFactory():相同

3.prepareBeanFactory():相同

4.postProcessBeanFactory():spring使用的AbstractApplicationContext的默认处理,没有提供实现,web提供了实现注册了特殊的处理器

5.invokeBeanFactoryPostProcessors():相同

6.registerBeanPostProcessors():相同

7.initMessageSource():相同

8.initApplicationEventMulticaster():相同

9.onRefresh():spring什么都没做,使用的AbstractApplicationContext的默认实现,web提供了创建web容器的过程

10.registerListeners():相同

11.finishBeanFactoryInitialization():相同

12.finishRefresh():spring主要做的事情是发布事件,web容器多了一步启动web容器

综上:web环境和spring环境启动容器流程基本相同,spring默认使用AbstractApplicationContext的实现,web多了properties解析,注册特殊处理器,创建webServer和启动webServer的过程。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容