詳細(xì)SpringBoot框架教程——SpringBoot源碼分析

本篇文章主要內(nèi)容
SpringBoot源碼構(gòu)建
驗(yàn)證SpringBoot源碼環(huán)境是否正常
閱讀源碼指導(dǎo)原則
SpringBoot啟動(dòng)流程源碼分析
視頻觀看戳??????

SpringBoot源碼構(gòu)建
1、安裝和配置好JDK環(huán)境環(huán)境變量(JDK8+);
2、安裝和配置好Gradle;官網(wǎng):https://gradle.org?
安裝gradle(需要先安裝JDK),Gradle直接解壓到一個(gè)目錄即完成安裝;
Gradle配置環(huán)境變量,配置GRADLE_HOME 和Path;
使用gradle -v 驗(yàn)證Gradle環(huán)境是否正常;
Springboot源碼從2.3.1版本開始由Maven改為了Gradle;
3、當(dāng)前我使用的是IDEA 2020.1.3 旗艦版
File -->Setting-->Editor-->File Encodings -->全部改為UTF-8
安裝代碼統(tǒng)計(jì)插件:Statistic
安裝英文翻譯插件:ECTranslation
4、下載SpringBoot源碼:https://github.com/spring-projects/spring-boot?
5、解壓下載下來(lái)的最新SpringBoot源碼:spring-boot-2.3.1.RELEASE.zip
6、進(jìn)入解壓后的目錄,比如:D:\project\opensource\spring-boot-2.3.1.RELEASE
7、閱讀解壓后的源碼目錄下的README.adoc文件,里面告訴了我們?nèi)绾螛?gòu)建源碼;
8、進(jìn)入源碼目錄的dos窗口,執(zhí)行:gradlew publishToMavenLocal
修改默認(rèn)下載gradle文件路徑
distributionUrl=file:///C:/Users/Administrator/.gradle/wrapper/gradle-6.4-bin.zip

執(zhí)行的時(shí)候,可能會(huì)遇到錯(cuò)誤,主要是因?yàn)橐恍┎寮膅radle網(wǎng)站下載失敗導(dǎo)致的,此時(shí)需要翻墻軟件(科學(xué)上網(wǎng)),才能下載成功;

出現(xiàn)上面的?git 的錯(cuò)誤,是因?yàn)閟pringboot源碼構(gòu)建需要保證源碼是處于一個(gè)git倉(cāng)庫(kù)中,所以我們把源碼納入本地倉(cāng)庫(kù)管理中,依次執(zhí)行如下命令:
創(chuàng)建.git目錄: git init?
將springboot源碼目錄加入暫存區(qū): git add *
提交springboot源碼提交到本地Git倉(cāng)庫(kù):?git commit -m 'springboot'

出現(xiàn)error: open:(.....)?Filename too long錯(cuò)誤,是因?yàn)槁窂教L(zhǎng)了,默認(rèn)是260個(gè)字符,解決方法:
git config core.longpaths true
接下來(lái)再進(jìn)行構(gòu)建:gradlew publishToMavenLocal

然后導(dǎo)入idea,等待加載完成,如果是第一次導(dǎo)入,需要下載一個(gè)依賴及插件,可能需要等待一段時(shí)間,會(huì)慢一些,如果某些插件下載失敗,也會(huì)報(bào)錯(cuò),通過啟動(dòng)翻墻軟件(科學(xué)上網(wǎng)),這樣保證從國(guó)外一些網(wǎng)站下載依賴和插件沒有問題,然后構(gòu)建成功;

顯示成功,接下來(lái)就可以開始在源碼的基礎(chǔ)上創(chuàng)建一個(gè)測(cè)試項(xiàng)目,進(jìn)行源碼的閱讀;
如果遇到源碼發(fā)乳Idea中報(bào)一個(gè)format的格式錯(cuò)誤的話,請(qǐng)dos窗口下執(zhí)行:
gradlew -p buildSrc format
驗(yàn)證SpringBoot源碼環(huán)境是否正常
創(chuàng)建一個(gè)spring-boot-zweb模塊,編寫springboot代碼并運(yùn)行,驗(yàn)證springboot源碼環(huán)境構(gòu)建是否正常;
加入springboot的依賴,根據(jù)需要添加依賴,舉例如下:

最后運(yùn)行spring-boot-zweb的main方法測(cè)試一下springboot環(huán)境是否正常?
一般情況下,第一次運(yùn)行會(huì)比較慢,后面的運(yùn)行會(huì)變快;
閱讀源碼指導(dǎo)原則
1、尋找入口
2、斷點(diǎn)跟蹤
3、先粗后細(xì)
4、精略結(jié)合
5、猜想驗(yàn)證
我們有了前面大量的源碼閱讀經(jīng)驗(yàn),相信大家對(duì)源碼閱讀并不感到陌生;
SpringBoot啟動(dòng)流程源碼分析
SpringBoot啟動(dòng)流程(SpringBoot啟動(dòng)原理)
啟動(dòng)流程主要分為三個(gè)部分:
第一部分進(jìn)行SpringApplication的初始化模塊,配置一些基本的環(huán)境變量、資源、構(gòu)造器、監(jiān)聽器;(了解一下)
第二部分實(shí)現(xiàn)了應(yīng)用具體的啟動(dòng)方案,包括啟動(dòng)流程的監(jiān)聽模塊、加載配置環(huán)境模塊、及核心的創(chuàng)建Spring上下文環(huán)境模塊;(掌握)
第三部分是自動(dòng)化配置模塊,該模塊是SpringBoot自動(dòng)配置的核心;(掌握)
宏觀步驟:(概括為18個(gè)小步驟)
https://www.processon.com/view/link/5dc15b71e4b0335f1e4eb6fe?
1、創(chuàng)建并啟動(dòng)計(jì)時(shí)監(jiān)控類StopWatch
2、初始化應(yīng)用上下文和異常報(bào)告集合(ConfigurableApplicationContext和Collection<SpringBootExceptionReporter>)
3、設(shè)置系統(tǒng)屬性 configureHeadlessProperty()
4、創(chuàng)建Spring運(yùn)行的監(jiān)聽器并啟動(dòng)
5、初始化默認(rèn)應(yīng)用參數(shù)類
6、準(zhǔn)備Spring環(huán)境
7、創(chuàng)建beanner打印類
8、創(chuàng)建應(yīng)用Spring上下文(也就是spring容器)
9、準(zhǔn)備異常報(bào)告器
10、準(zhǔn)備應(yīng)用上下文(也就是spring容器)
11、刷新上下文(也就是spring容器)
12、應(yīng)用上下文刷新后置處理(也就是spring容器)
13、停止計(jì)時(shí)監(jiān)控類
14、輸出日志信息
15、發(fā)布應(yīng)用上下文啟動(dòng)完成事件
16、執(zhí)行所有Runner運(yùn)行器(如果實(shí)現(xiàn)CommandLineRunner接口)
17、發(fā)布應(yīng)用上下文就緒事件
18、完成返回容器對(duì)象
SpringBoot啟動(dòng)流程源碼分析
1、入口main方法執(zhí)行;

2、執(zhí)行run方法;

3、看一下run(new Class<?>[] { primarySource }, args);方法;

//這個(gè)run方法主要做兩件事情:
//1、new了一個(gè)SpringApplication 這么一個(gè)對(duì)象;
(1)?把main方法這個(gè)類賦給一個(gè)成員變量;
(2)?判斷是java項(xiàng)目還是web項(xiàng)目;
(3)?設(shè)置了一個(gè)初始化器和事件發(fā)送的監(jiān)聽器;
//2、然后執(zhí)行SpringApplication對(duì)象的run()方法;
4、先看做的第一件事情,new了一個(gè)SpringApplication對(duì)象

這里面用到了一種類似于Java SPI機(jī)制的方式掃描META-INF/spring.factories這個(gè)文件,并且加載?ApplicationContextInitializer、ApplicationListener 接口實(shí)例;
(1)ApplicationContextInitializer 這個(gè)類當(dāng)springboot上下文Context初始化完成后會(huì)調(diào)用;
(2)ApplicationListener 當(dāng)springboot啟動(dòng)時(shí)事件change后都會(huì)觸發(fā)
我們可以自定義實(shí)現(xiàn)ApplicationContextInitializer、ApplicationListener 接口,然后運(yùn)行時(shí)會(huì)被觸發(fā)執(zhí)行;
5、然后我們看做的第二件事情,執(zhí)行new出來(lái)的SpringApplication對(duì)象的run()方法;



6、接下來(lái)我們重點(diǎn)看一下run方法里面的幾個(gè)重要步驟,首先看看紅色標(biāo)記的創(chuàng)建spring容器上下文context = createApplicationContext();這段代碼主要是根據(jù)項(xiàng)目類型創(chuàng)建Spring上下文,并且會(huì)注入幾個(gè)核心組件類;

Web類型項(xiàng)目創(chuàng)建上下文對(duì)象 AnnotationConfigServletWebServerApplicationContext,這里會(huì)把?ConfigurationClassPostProcessor 、
AutowiredAnnotationBeanPostProcessor 等一些核心組件加入到Spring容器,這其實(shí)已經(jīng)是spring?ioc容器的源碼,如果了解spring ioc源碼,那么對(duì)springboot源碼的閱讀會(huì)有很大的幫助;
7、然后再看一下run方法里面另一個(gè)比較重要的步驟,紅色標(biāo)記的創(chuàng)建和刷新spring容器refreshContext()方法,
refreshContext(context) 這個(gè)方法,該方法啟動(dòng)spring的代碼加載了bean,還啟動(dòng)了內(nèi)嵌的web容器;

接下來(lái)進(jìn)入到Spring ioc容器刷新和創(chuàng)建的12個(gè)步驟的源碼中,AbstractApplicationContext - >refresh()方法,在這12個(gè)步驟中,這里主要看一下onRefresh() 這個(gè)方法,但是發(fā)現(xiàn)這個(gè)方法里面什么都沒有,顯然是一個(gè)鉤子方法,它會(huì)鉤到它子類重寫onRefresh()方法,所以去看子類里面的onRefresh()方法;
由于我們這里是一個(gè)Web項(xiàng)目,所以就可以看到 ServletWebServerApplicationContext 這個(gè)類,這個(gè)類下面的 onRefresh() 方法:

繼續(xù)看下getWebServletFactory() 這個(gè)方法,這里面選擇出哪種類型的web容器

再回頭去看factory.getWebServer(getSelfInitializer()) ,轉(zhuǎn)到定義就會(huì)看到很熟悉的名字tomcat

內(nèi)置的Servlet容器就是在onRefresh() 方法里面啟動(dòng)的,至此一個(gè)Servlet容器就啟動(dòng)OK了;
總結(jié):
1、new了一個(gè)SpringApplication對(duì)象,使用一種類似于SPI機(jī)制的技術(shù)加載ApplicationContextInitializer、ApplicationListener 接口實(shí)例;(非重點(diǎn))
2、調(diào)用SpringApplication.run() 方法,run方法里面大概有18個(gè)小步驟;
3、調(diào)用createApplicationContext()方法創(chuàng)建Spring IOC上下文對(duì)象,創(chuàng)建上下文對(duì)象同時(shí)會(huì)注冊(cè)spring的核心組件類;
ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor等;
4、調(diào)用refreshContext() 方法啟動(dòng)Spring容器(12步)和內(nèi)置的Servlet容器;
如果想更深入的學(xué)習(xí)springboot,奉上springboot全套視頻教程,視頻學(xué)習(xí)效果更佳,走過路過別忘素質(zhì)三連哦~~

