SpringBoot 的啟動(dòng)引導(dǎo)類(lèi)真的是XXApplication嗎?
來(lái)源:https://my.oschina.net/floor/blog/4301613
1. 引言
SpringBoot項(xiàng)目中的啟動(dòng)類(lèi),一般都是XXApplication,例如StatsApplication,UnionApplication。每個(gè)項(xiàng)目的啟動(dòng)類(lèi)名稱(chēng)都不一樣。但是它的啟動(dòng)類(lèi)真的是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文件的入口類(lèi)。
解壓jar包,查看META-INF/Manifest.mf過(guò)程如下:
重要信息如下
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.shanyuan.StatsApplication
也就是說(shuō):org.springframework.boot.loader.JarLauncher是SpringBoot的啟動(dòng)類(lèi)!
下面瀏覽下JarLauncher
3. 瀏覽JarLauncher
3.1 找到JarLauncher
進(jìn)入IDEA,Ctrl+N查找JarLauncher,竟然找不到!!
進(jìn)入 https://search.maven.org/classic/#advancedsearch 查詢(xún)JarLauncher
在查詢(xún)結(jié)果找到spring下的項(xiàng)目
確定JarLauncher位于spring-boot-loader下。為了方便查看源碼,在pom中引入
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-loaderartifactId>
<scope>providedscope>
dependency>
3.2.JarLauncher說(shuō)明
JarLauncher作為引導(dǎo)類(lèi) ,當(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
2. ClassLoader classLoader = createClassLoader(getClassPathArchives());
創(chuàng)建ClassLoader。
getClassPathArchives 核心判斷是 isNestedArchive方法。
isNestedArchive被JarLauncher覆寫(xiě)了。其實(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ō),只要 滿(mǎn)足以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)類(lèi),即XXXApplication的main方法。
4.總結(jié)
SpringBoot項(xiàng)目的實(shí)際啟動(dòng)類(lèi)是org.springframework.boot.loader.JarLauncher。
在JarLauncher內(nèi)部通過(guò)反射調(diào)用XXApplication類(lèi)的main方法。
具體實(shí)現(xiàn)位于 MainMethodRunner中。
-END-
我是武哥,最后給大家免費(fèi)分享我寫(xiě)的 10 萬(wàn)字 Spring Boot 學(xué)習(xí)筆記(帶完整目錄)以及對(duì)應(yīng)的源碼。這是我之前在 CSDN 開(kāi)的一門(mén)課,所以筆記非常詳細(xì)完整,我準(zhǔn)備將資料分享出來(lái)給大家免費(fèi)學(xué)習(xí),相信大家看完一定會(huì)有所收獲(下面有下載方式)。
可以看出,我當(dāng)時(shí)備課非常詳細(xì),目錄非常完整,讀者可以手把手跟著筆記,結(jié)合源代碼來(lái)學(xué)習(xí)?,F(xiàn)在免費(fèi)分享出來(lái),有需要的讀者可以下載學(xué)習(xí),就在下面的公眾號(hào)Java禿頭哥里回復(fù):筆記,就行。
如有文章對(duì)你有幫助,
在看和轉(zhuǎn)發(fā)是對(duì)我最大的支持!
關(guān)注Java禿頭哥
只有禿頭才能更強(qiáng)
點(diǎn)贊是最大的支持





