通常我們都是在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