springboot原始碼(4)
我們上3個篇章寫了springboot的自動裝配、servlet元件的注入以及web容器實現內嵌的原理,現在我們來看springboot啟動過程中到底做了些什麼,也就是開啟我們的run方法:
這裡我們可以看到我們的run方法會new出一個springboot自己的一個容器,然後執行裡面的run方法,這個args引數就是我們執行專案時所帶的引數;因為這裡new了一個springboot容器,所以我們開啟SpringApplication,看裡面初始化了什麼東西:
可以看到,其實springboot容器裡並沒有做什麼事,無非是做些判斷,這些判斷大多是通過判斷容器裡是否有某個類從而進行確定,比如判斷是web應用裡面檢查的就是容器裡是否有servlet類,是否載入了spring-web這個spring原始碼專案;而這裡的初始化檔案我們可以開啟:
這兩個初始化大類大致上的作用是初始化監聽器,下面的這個類是全域性的一個監聽器,通過觀察者的一個設計模式,我們可以釋出各種各樣的事件,然後進行監聽,這裡就不做過長的講解(畢竟到現在我們的run方法還沒講==!),有興趣的可以開啟這些初始化類並學習spring裡的監聽器內容;
最後的這個找配置類其實就是通過拿到異常方法的呼叫棧,找到是否有main方法,再通過main方法返回你的主配置類名:
至此,我們應該大致知道在run方法執行前springboot做了哪些操作,接下來開啟springboot容器裡的這個run方法:
這裡挑選我覺得比較實用的內容來講:
首先是這個從配置檔案讀取的SpringApplicationRunListener介面的實現類,
這裡我們自定義一個MyRunListener繼承這個介面,重寫介面原本的方法starting、started、running等等的方法即可讓容器在啟動前做一些自定義的操作,注意要把這個類寫進
這個配置檔案中;
其實在準備初始化階段springboot做的就是釋出監聽;
我們開啟refreshContext(context);看看在spring容器的初始化方面springboot做了哪些改進:
可以看到這裡呼叫的super.refresh其實就是spring裡本身的refresh()極度不要臉的照搬過來哈,我們再看裡面的onRefresh方法
因為這個方法是spring容器在初始化後提供我們可以對容器做出修改的方法
可以看到,springboot在初始化時做的唯一改變就是添加了對web容器的判斷,看其是否內嵌:
這裡就很好地結合了之前講的內嵌web容器以及注入servlet元件的原理了;先看一下web容器,如果是外部容器,即war包啟動,通過web容器帶動IOC啟動,想想之前的java Config技術,其實就是利用WebApplicationInitializer這個介面,實現這個介面的類在tomcat執行時會呼叫裡面的onStartup方法,我們重寫這個onStartup方法,在裡面建立web應用上下文,並加入監聽器,在初始化context的時候會執行run方法,即啟動IOC容器,所以判斷專案是jar包啟動還是war包啟動,如果沒拿到servletcontext,那就是以jar包啟動:
看這裡的getSelfInitializer(),初始化的正好對應開啟的就是我們之前將servlet元件注入的裡的onStartup方法,我們從spring容器裡拿到所有實現了SevletContextInitializer的bean,再執行onStartup方法,把這些元件加入到servletcontext中,最後再通過getWebServer方法啟動和獲取web容器;也就是內嵌web容器和外部容器正好相反,內嵌的web容器是通過IOC來啟動web容器,而外部容器是通過web容器來啟動IOC;
至此,springboot在初始化Spring容器所作的貢獻已然結束,我們再回到run方法裡,可以看到後面無非就是列印一些日誌輸出以及一些容器啟動後的監聽器監聽事件,所有簡單總結下run方法裡的作用:一、初始化springboot容器(1、判斷上下文環境;2、載入Spring.factories配置檔案裡的ApplicationContextInitializer和ApplicationListener;3、找到main方法所在類);二、啟動Sring容器(釋出各式各樣的監聽器監聽、重寫Spring裡的onReference方法:判斷是否啟動內嵌tomcat)
最後,再附上一張在網上找的Springboot的啟動流程圖:
&n