通常我们都是在main方法中调用SpringApplication.run()方法启动SpringBoot应用的,
今天来看一下启动过程中都干了些什么。上图。
<a href="https://s5.51cto.com/wyfs02/M00/08/01/wKiom1nZgFzidkJ9AADZ1ECFUm0224.png" target="_blank"></a>
<a href="https://s5.51cto.com/wyfs02/M02/A6/B3/wKioL1nZgA2icE8MAABtw0yNx-c157.png" target="_blank"></a>
<a href="https://s5.51cto.com/wyfs02/M01/08/01/wKiom1nZgF2wm0VCAACCYRdplLY602.png" target="_blank"></a>
<a href="https://s2.51cto.com/wyfs02/M02/A6/B3/wKioL1nZgA7zw5ENAAAgKuEJD00040.png" target="_blank"></a>
大致分为两步,第一步new一个SpringApplication对象,第二步调用其run方法。
在创建SpringApplication对象的时候做了以下几件事情:
(1)判断应用是不是Web应用,判断的依据是classpath中有没有Servlet和ConfigurableWebApplicationContext,具体来讲就是,能不能成功获取到它们的Class对象
(2)设置Initializer和Listener
(3)判断main方法
这里有必要了解一下ApplicationContextInitializer和ApplicationListener是干什么的
<a href="https://s2.51cto.com/wyfs02/M01/08/01/wKiom1nZgyjwBfIiAAEjexBMnC8727.png" target="_blank"></a>
首先,ApplicationContextInitializer它是初始化Spring ConfigurableApplicationContext的时候的回调接口,它会先于ConfigurableApplicationContext的refresh()方法被调用。而我们知道ConfigurableApplicationContext的refresh()方法是在AbstractApplicationContext中实现的。
<a href="https://s4.51cto.com/wyfs02/M01/A6/B3/wKioL1nZh_XBeYx6AACs5LS3odA910.png" target="_blank"></a>
ApplicationListener是一个基于标准的EventListener的事件监听器,用的是观察者模式。
这两步都有一个共同点就是都调用getSpringFactoriesInstances()方法,下面看下:
<a href="https://s2.51cto.com/wyfs02/M01/08/01/wKiom1nZiZHAyZ65AACFiKeXUzw475.png" target="_blank"></a>
<a href="https://s2.51cto.com/wyfs02/M01/A6/B3/wKioL1nZiULSIN5fAAEHKx47UZw843.png" target="_blank"></a>
<a href="https://s2.51cto.com/wyfs02/M01/A6/B3/wKioL1nZiUKw-G5-AAApJ-2OdxY502.png" target="_blank"></a>
它的作用就是从classpath中所有的META-INF/spring.factories文件中找到指定Key的值。(注意:是所有的META-INF/spring.factories)
然后将其以List形式返回,并实例化它们。
在我们的例子中,这两次找的key值分别是:org.springframework.context.ApplicationContextInitializer和org.springframework.context.ApplicationListener
我们具体看一下它们的值是什么
<a href="https://s4.51cto.com/wyfs02/M00/A6/B3/wKioL1nZiqrCIFmKAACIpN4gLo4351.png" target="_blank"></a>
<a href="https://s5.51cto.com/wyfs02/M01/08/01/wKiom1nZivqQMSN9AADNjNTdV3A006.png" target="_blank"></a>
总之呢,我们可以知道在容器启动的过程中,ApplicationContextInitializer的initialize()方法在AbstractApplicationContext的refresh()方法之前被调用。
到此为止,SpringApplication对象已经创建好了,接下来调用其run()方法。
这里先来了解一下SpringApplicationRunListener,它是SpringApplication#run()方法的一个监听器,并没有什么实质性的作用。
<a href="https://s5.51cto.com/wyfs02/M01/A6/B4/wKioL1nZneKQCAk-AAD7uxi43BQ489.png" target="_blank"></a>
第1步、创建一个ApplicationArguments对象,它是对我们运行时传进来的参数的一个封装
第2步、创建并配置Environment。这里,如果是web环境,则创建StandardServletEnvironment,否则创建一个StandardEnvironment
<a href="https://s1.51cto.com/wyfs02/M01/08/02/wKiom1nZoC6CHU5QAAAsrSU5bKA587.png" target="_blank"></a>
<a href="https://s4.51cto.com/wyfs02/M02/08/03/wKiom1nZsvuic9pmAAA4YBgkOlU677.png" target="_blank"></a>
第3步、打印Banner
第4步、初始化ApplicationContext。这里,如果是web环境,则实例化AnnotationConfigEmbeddedWebApplicationContext,否则实例化AnnotationConfigApplicationContext。
<a href="https://s4.51cto.com/wyfs02/M00/A6/B4/wKioL1nZoSWzZzOtAACeUjOpJl8745.png" target="_blank"></a>
<a href="https://s4.51cto.com/wyfs02/M01/08/02/wKiom1nZoXSyA_4qAABnNvW1UG4956.png" target="_blank"></a>
第5步、创建FailureAnalyzers对象
第6步、准备上下文
(1)如果BeanNameGenerator不为空,将其注册到BeanFactory。(PS:其实就是ApplicationContext)
(2)调用所有ApplicationContextInitializer的initialize()方法
(3)将ApplicationArguments和Banner的实例注册到Context
(4)加载Sources
<a href="https://s3.51cto.com/wyfs02/M02/A6/B4/wKioL1nZpMeTiUFAAAC1ezz2RHI959.png" target="_blank"></a>
<a href="https://s3.51cto.com/wyfs02/M00/08/02/wKiom1nZpRbTagulAACd5KPPD0o329.png" target="_blank"></a>
<a href="https://s3.51cto.com/wyfs02/M00/A6/B4/wKioL1nZpMfBbGHeAACrp2K3YEM870.png" target="_blank"></a>
到这里,sources中所有的Bean都被加载到Context中了
第7步、刷新Context。这里它直接调用的AbstractApplicationContext的refresh()方法,前面的文章已经介绍过了,这里不再赘述。
<a href="https://s4.51cto.com/wyfs02/M00/A6/B4/wKioL1nZpdDTOC3HAAA-PXfvQjE895.png" target="_blank"></a>
<a href="https://s4.51cto.com/wyfs02/M02/08/02/wKiom1nZpiDQyWCtAACy0WqRd7E939.png" target="_blank"></a>
第8步、调用Context中所有的ApplicationRunner和CommandLineRunner
<a href="https://s4.51cto.com/wyfs02/M02/A6/B4/wKioL1nZpsvj05_cAACcNlLHtrE549.png" target="_blank"></a>
到此为止,启动完成!!!
总结:
第1步、所有的源对象(source)保存到Set<Object> sources成员变量中
第2步、判断是否web环境
第3步、设置Initializer和Listener
第4步、判断main方法
第5步、创建ApplicationArguments对象
第6步、创建并配置环境
第7步、创建Banner
第8步、创建ApplicationContext
第9步、配置ApplicationContext。在这一步中会回调所有的ApplicationContextInitializer,还会注册一些特殊的Bean到Context,最重要的是会加载sources中所配置的所有的Bean到Context中。
第10步、刷新Context。这里直接调用AbstractApplicationContext的refresh()方法。
第11步、调用容器中所有的ApplicationRunner和CommandLineRunner
本文转自 手不要乱摸 51CTO博客,原文链接:http://blog.51cto.com/5880861/1970708