Spring Boot 啟動(dòng)類真的是XXApplication?

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
1. 引言
SpringBoot項(xiàng)目中的啟動(dòng)類,一般都是XXApplication,例如StatsApplication,UnionApplication。
每個(gè)項(xiàng)目的啟動(dòng)類名稱都不一樣。
但是它的啟動(dòng)類真的是XXApplication嗎?

2. META-INF/Manifest.mf文件
jar文件實(shí)際上是class文件的zip壓縮存檔。jar并不能表達(dá)應(yīng)用程序的便簽信息.
META-INF/Manifest.mf文件提供存檔的便簽信息,Manifest.mf有 Main-Class,用來(lái)標(biāo)明jar文件的入口類。點(diǎn)擊這里獲取一份完整的 Spring Boot 學(xué)習(xí)筆記。
解壓jar包,查看META-INF/Manifest.mf過(guò)程如下:

重要信息如下
Main-Class:?org.springframework.boot.loader.JarLauncher
Start-Class:?com.shanyuan.StatsApplication
也就是說(shuō):org.springframework.boot.loader.JarLauncher 才是 Spring Boot 的啟動(dòng)類!
不熟悉 Spring Boot 的可以看下這個(gè)倉(cāng)庫(kù):https://github.com/javastacks/spring-boot-best-practice
下面瀏覽下JarLauncher
3. 瀏覽JarLauncher
3.1 找到JarLauncher
進(jìn)入IDEA,Ctrl+N查找JarLauncher,竟然找不到?。?/p>
進(jìn)入 https://search.maven.org/classic/#advancedsearch 查詢JarLauncher

在查詢結(jié)果找到spring下的項(xiàng)目

確定JarLauncher位于spring-boot-loader下。為了方便查看源碼,在pom中引入
????org.springframework.boot
????spring-boot-loader
????provided
3.2.JarLauncher說(shuō)明
JarLauncher作為引導(dǎo)類 ,當(dāng)調(diào)用java -jar 命令時(shí),將調(diào)用main方法,實(shí)際上調(diào)用的是 JarLauncher#launch方法,該方法繼承與org.springframework.boot.loader.Launcher
簡(jiǎn)化層次關(guān)系為:

JarLauncher#launch代碼如下
protected?void?launch(String[]?args)?throws?Exception?{
???JarFile.registerUrlProtocolHandler();
???ClassLoader?classLoader?=?createClassLoader(getClassPathArchives());
???launch(args,?getMainClass(),?classLoader);
}
聚句解析
1,.JarFile.registerUrlProtocolHandler();
Spring Boot生成的FAT jar,在被java -jar 引導(dǎo)時(shí),其內(nèi)部的jar文件無(wú)法被sun.net. www.protocol .jar.Handler處理。
所以SpringBoot實(shí)現(xiàn)了,org.springframework.boot.loader.jar.Handler
JarFile.registerUrlProtocolHandler(),就注冊(cè) org.springframework.boot.loader.jar.Handler
創(chuàng)建ClassLoader。
getClassPathArchives 核心判斷是 isNestedArchive方法。
isNestedArchive被JarLauncher覆寫了。
其實(shí)現(xiàn)如下:
static?final?String?BOOT_INF_CLASSES?=?"BOOT-INF/classes/";
static?final?String?BOOT_INF_LIB?=?"BOOT-INF/lib/";
@Override
protected?boolean?isNestedArchive(Archive.Entry?entry)?{
???if?(entry.isDirectory())?{
??????return?entry.getName().equals(BOOT_INF_CLASSES);
???}
???return?entry.getName().startsWith(BOOT_INF_LIB);
}
也就是說(shuō),只要 滿足以BOOT-INF/classes/和BOOT-INF/lib/都是classLoader加載的范圍。
解壓的jar,查看也與只對(duì)應(yīng)

3. launch(args, getMainClass(), classLoader);
protected?void?launch(String[]?args,?String?mainClass,?
????????????????ClassLoader?classLoader)
??????throws?Exception?{
???Thread.currentThread().setContextClassLoader(classLoader);
???createMainMethodRunner(mainClass,?args,?classLoader).run();
}
查看createMainMethodRunner的run方法,如下:
public?class?MainMethodRunner?{
????//?省略部分代碼
????public?void?run()?throws?Exception?{
???Class>?mainClass?=?Thread.currentThread().getContextClassLoader()
?????????.loadClass(this.mainClassName);
???????Method?mainMethod?=?
???????????mainClass.getDeclaredMethod("main",?String[].class);
???????mainMethod.invoke(null,?new?Object[]?{?this.args?});
????}
}
其中mainClass,來(lái)自/META-INF/MANIFEST.MF中的Start-Class屬性。
即,JarLauncher是同進(jìn)程內(nèi),通過(guò)反射調(diào)用Start-Class對(duì)應(yīng)類,即XXXApplication的main方法。
4.總結(jié)
Spring Boot 項(xiàng)目的實(shí)際啟動(dòng)類是org.springframework.boot.loader.JarLauncher。
在JarLauncher內(nèi)部通過(guò)反射調(diào)用XXApplication類的main方法。
具體實(shí)現(xiàn)位于 MainMethodRunner中。最后,關(guān)于?Spring Boot?系列教程可以關(guān)注公眾號(hào)Java技術(shù)棧獲取閱讀。
作者:溫安適
來(lái)源:https://my.oschina.net/floor/blog/4301613






關(guān)注Java技術(shù)棧看更多干貨


