1.寫在前面
Spring作爲風靡世界的優秀框架,很早就想研究研究Spring源碼了。最近親手搭建了Spring環境,從下載源碼到編譯到改動源碼測試demo跑通,有些踩坑和心得需要記錄一下,也與大家分享一下。
注:筆者在2臺不同電腦上均告成功,但是也不敢保證各位看官一定能成功,如果失敗請輕拍磚。不過相信對各位編譯Spring還是有一定幫助的,廢話不多說,Let’s Go Go Go!
2.編譯前需要準備的環境和工具。
- 操作系統:俺是在Win10上編譯的
- Java環境:1.8.0_151
注意:有網友說JDK版本不能過高,比如jdk1.8_20和jdk1.8_191,因此當遇到一堆 0x000000: xxxxxxxx 之類的錯誤時,請留意你的JDK版本。 - 源碼下載:講真,想在GitHub上下載,太難了,筆者試了若干次沒有成功。逼不得已,去碼雲上下載的。如果看官也被逼上"碼雲",請注意,在搜索框輸入:Spring-Framework,然後請選擇這個庫:
碼雲極速下載 / Spring-Framework
,然後挑選需要的源碼。筆者選擇的是:v5.0.0.RELEASE,然後通過zip方式下載的。
- Gradle:Spring是通過Gradle構建的,因此需要下載安裝一個Gradle。很簡單,下載解壓,配置環境變量即可。
- idea:筆者使用的2019 1.1版本
3.具體步驟
-
相信你已經安裝好了JDK,idea,讓我們往下。
-
將下載好的源碼包放到一個單獨目錄,解壓之。根目錄下留心下面幾個文件。
- build.gradle :這是和Spring構建有關的文件,後面會有所修改。
- import-into-idea.md :這是關於導入idea的一個說明文件。裏面有關於導入idea的信息,這是我們需要的,裏面有個命令馬上就會用到。
-
在 import-into-idea.md文件中,有這麼一句話
Precompile spring-oxm with ./gradlew :spring-oxm:compileTestJava
說得很清楚,需要預先編譯spring-oxm模塊,使用gradlew :spring-oxm:compileTestJava這個命令。好照着做。但是等等,1號坑出現,如果不想編譯後出現類似這樣的錯誤
Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002
那麼一定要在 管理員窗口 中執行gradlew :spring-oxm:compileTestJava命令。如下:
-
執行命令後,從上面圖片中可以得到4個信息:
- 其一:會自動下載gradle-4.1-bin.zip,筆者曾試過,就算本機安裝有一個gradle,配置好環境變量,這裏spring也會去下載一個。不知道是正常還是不正常。但是你還是應該去gradle官網下載一個gradle,因爲待會兒導入idea要用,不建議用idea自帶的。
- 其二:注意2號坑出現,你下載安裝的gradle版本不能太高,過高的話,導入idea後,會出現各種頭疼的問題導致你心態炸裂。那麼下載什麼版本呢?其實spring已經告訴你了,去下載一個和他自動安裝的那個版本就好了。而且v5.0.0.RELEASE對應的gradle版本是gradle-4.1,其他的可不一定,以spring自己打印出來的版本爲準。
- 其三:spring會自己去下載一些包來支撐構建,而從上面圖片來看,下載地址是https://repo.spring.io/plugins-release。一般說來速度不會很慢,但是如果速度慢怎麼辦?拿鞭子抽它,讓它加速。下面第5步,是可選步驟,如果很慢的話,可以按照第5步操作,如果不慢,就跳過。一般說來,這一步預編譯步驟,不應該超過10分鐘。
- 其四:編譯的時候,有個進度條,和打印一些信息的東西,有時候界面會看似卡死不動,其實是在正常進行的,敲一下回車,就可以看到了,不會打斷編譯過程的,放心敲。
-
【可選步驟】加速編譯spring-oxm模塊。原理就是添加一個阿里雲鏡像。如果你發現下載速度很慢,Ctrl + C退出編譯,然後在spring源碼包下,打開build.gradle文件,像下圖一樣,將紅框中的部分添加到文件中。
注意點:
- 綠色框中的是文件本來就有的,不要刪掉它,因爲有些插件包,阿里雲並沒有同步完全,如果刪掉,很可能下載不下來而導致失敗。另外它的順序應該如圖一樣,排在最後。
2.allprojects那個框,也保持如圖中的位置,不要移動到plugins上面。
再一次執行gradlew :spring-oxm:compileTestJava命令。注意在管理員窗口執行。
- 綠色框中的是文件本來就有的,不要刪掉它,因爲有些插件包,阿里雲並沒有同步完全,如果刪掉,很可能下載不下來而導致失敗。另外它的順序應該如圖一樣,排在最後。
-
稍等一會兒,不管有沒有執行第5步,你應該都可以得到一個編譯成功的結果。如下:
只不過進了第5步的話,應該還是會快點,在筆者的後面幾次實驗中,只用了2分半鐘。
另外,預編譯成功後,可以打開源碼包看看,其實有些核心模塊,比如core,context,已經編譯出jar包了,但是像jdbc等模塊,是沒有的,因此可以導入idea來繼續編譯,不過應該是可以繼續在管理員窗口編譯的,有興趣的可以自行嘗試。 -
導入idea之前,覈實一下是否按照第4步中,安裝好了gradle,如果是,需要配置一下繼續go go go
-
打開idea,在WelCome頁面,點擊open,選擇編譯好的Spring源碼根目錄,自動彈出如下gradle項目嚮導,按下圖配置即可。ps:如果沒有,請覈實自己的idea是否安裝了gradle插件。
-
點擊OK,idea會自動構建環境,下載包等,此時等待。如果按照上面的步驟來,此處應該是能成功的。不然很多坑就會在這裏應驗 ^ _ ^。
-
等到IDEA構建好之後,出現如上圖的幾個綠條。那麼就可以打開右側Gradle面板,進行編譯了。如圖:
- 可以選擇點擊1號框,手動輸入命令編譯
- 也可以雙擊2號框,直接編譯。
-
但是注意,3號坑出現。此坑說來話長,但是不得不說。Spring源碼有當前master分支,和歷史各個分支,還有RELEASE版本。如果你是選擇clone master分支來編譯,那麼是不會編譯生成文檔包和源碼包的。如果是歷史分支,Release版本,則會做這些事情,比如筆者目前選擇的v5.0.0.RELEASE版本。但是,在Win10系統上,編譯生成文檔包,會遇到一些非常棘手的事情,如果你嘗試這樣編譯了,會發現控制檯打印出一些???和亂碼,並且最後編譯失敗(其實也不算失敗,文檔失敗了而已)得到類似這樣的錯
Execution failed for task ‘:asciidoctor’.
…
(SystemCallError) Unknown error 123 - FindFirstFile這個錯是因爲Win10路徑的一些兼容問題,很難解決,如果只是爲了閱讀源碼,沒有必要在這個問題糾結。如果是正式的用途,那可以到Linux環境進行編譯。
那麼我們的解決方式就是:跳過文檔源碼包編譯
找到如下2個地方,註釋掉(另外看官們可以去GitHub上瞧瞧,master分支上沒有下面2個東西,所以編譯master分支時不會遇到3號坑,但編譯Release版本,則會遇到):
-
現在又可以雙擊build進行編譯了,不會出現剛剛一堆紅色???了,但是世界似乎仍不安靜,控制檯在打印一些白色FAILED。這是因爲編譯測試程序出了問題。這裏筆者曾經嘗試解決,但是當解決了一個模塊後,另一個模塊的測試又會出問題,時間有限,這裏只給出解決思路和1個例子。
在測試程序失敗後,會出具一份Report,在控制檯可以看到連接,可以複製出來在瀏覽器打開,可以看到報錯信息,哪些類失敗等。
比如這個問題:Execution failed for spring ':spring-webflux:test'
解決辦法是:將
compile"com.fasterxml.jackson.module:jackson-module-kotlin:2.9.0"
放入spring-webflux的gradle dependencies 節點中。
由於筆者只是研究一下Spring源碼,於是選擇跳過測試程序,有興趣的可繼續自行解決。進行下一步
-
跳過測試。點擊第10步1號框,手動輸入下面命令來跳過測試執行編譯。
build -x test
這樣只編譯源碼,就很快了,快的幾十秒,慢點幾分鐘就打完收工。
-
編譯完畢,下一步就是新建一個模塊來測試一下啦。
- new -> module -> gradle -> next -> 輸入artifactID -> 確定
- 向自動生成的gradle文件的dependencies中添加一行:compile(project(’:spring-context’))
- 新建測試類
public class HelloSpring { public void say(){ System.out.println("hello spring"); } }
public class TestClient { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.refresh(); context.register(HelloSpring.class); HelloSpring helloSpring = (HelloSpring)context.getBean("helloSpring"); helloSpring.say(); } }
-
點擊運行。nice,4號坑出現。應該會得到下面一個錯誤
Error:(26, 38) java: 找不到符號 符號: 類 InstrumentationSavingAgent 位置: 程序包 org.springframework.instrument
解決辦法是:將下圖本來爲optional的,改爲compile
-
再次點擊運行,運行成功。v5.0.0.RELEASE版本編譯到此結束。
-
都運行成功了,爲什麼還有下一點呢?因爲還有5號坑,但是此坑在編譯v5.0.0.RELEASE版本的時候,並沒有出現。而出現在了編譯master分支上,目前master版本是5.2.2,當運行測試程序的時候,很可能得到這個錯誤:
Error:(347, 51) java: 找不到符號 符號: 變量 CoroutinesUtils 位置: 類 org.springframework.core.ReactiveAdapterRegistry.CoroutinesRegistrar
這是因爲有個包,spring沒有幫你打進去,需要自己添加,如下操作:
- 找到Spring-core模塊,右鍵新建一個lib文件夾
- 按照如下圖所示,將包複製過去
- 打開spring-core.gradle文件,將
compile fileTree(dir:'lib',includes:['*jar'])
添加到dependencies,如下圖
然後idea觸發自動編譯。編譯好後,運行測試程序,問題解決。
4.總結
以上都是