詳解SpringBoot可執(zhí)行Jar包運(yùn)行原理
打可執(zhí)行 Jar 包
將 Spring Boot 應(yīng)用打成可執(zhí)行 Ja r包很容易,只需要在 pom 中加上一個(gè) Spring Boot 提供的插件,然后在執(zhí)行mvn package即可。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
注意:
如果你的項(xiàng)目沒(méi)有繼承spring-boot-starter-parent這個(gè)POM,你需要做如下配置,將目標(biāo)綁定到repackage。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
關(guān)于這個(gè)插件的詳細(xì)使用,可以參考官網(wǎng)
運(yùn)行完mvn package后,我們會(huì)在 target 目錄下看到兩個(gè) jar 文件。myproject-0.0.1-SNAPSHOT.jar 和 myproject-0.0.1-SNAPSHOT.jar.original。第一個(gè) jar 文件就是我們應(yīng)用的可執(zhí)行 jar 包,第二個(gè) Jar 文件是應(yīng)用原始的 jar 包。
可執(zhí)行 Jar 包內(nèi)部結(jié)構(gòu)
將打出來(lái)的可執(zhí)行 Jar 解壓開(kāi)我們能看到下面的結(jié)構(gòu):
可執(zhí)行 jar 目錄結(jié)構(gòu)
├─BOOT-INF
│ ├─classes
│ └─lib
├─META-INF
│ ├─maven
│ ├─app.properties
│ ├─MANIFEST.MF
└─org
└─springframework
└─boot
└─loader
├─archive
├─data
├─jar
└─util
我們先來(lái)重點(diǎn)關(guān)注兩個(gè)地方:META-INF 下面的 Jar 包描述文件和 BOOT-INF 這個(gè)目錄。
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: xxxx Start-Class: com.xxxx.AppServer Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Version: 2.1.6.RELEASE Created-By: Apache Maven 3.3.9 Build-Jdk: 1.8.0_73 Main-Class: org.springframework.boot.loader.JarLauncher
在上面我們看到一個(gè)熟悉的配置Main-Class: org.springframework.boot.loader.JarLauncher。我們大概能猜到這個(gè)類(lèi)是整個(gè)系統(tǒng)的入口。
再看下 BOOT-INF 這個(gè)目錄下面,我們會(huì)發(fā)現(xiàn)里面是我們項(xiàng)目打出來(lái)的 class 文件和項(xiàng)目依賴(lài)的 Jar 包??吹竭@里,你可能已經(jīng)猜到 Spring Boot 是怎么啟動(dòng)項(xiàng)目的了。
JarLauncher
public class JarLauncher extends ExecutableArchiveLauncher {
static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
static final String BOOT_INF_LIB = "BOOT-INF/lib/";
public JarLauncher() {
}
protected JarLauncher(Archive archive) {
super(archive);
}
@Override
protected boolean isNestedArchive(Archive.Entry entry) {
if (entry.isDirectory()) {
return entry.getName().equals(BOOT_INF_CLASSES);
}
return entry.getName().startsWith(BOOT_INF_LIB);
}
public static void main(String[] args) throws Exception {
//項(xiàng)目入口,重點(diǎn)在launch這個(gè)方法中
new JarLauncher().launch(args);
}
}
//launch方法
protected void launch(String[] args) throws Exception {
JarFile.registerUrlProtocolHandler();
//創(chuàng)建LaunchedURLClassLoader。如果根類(lèi)加載器和擴(kuò)展類(lèi)加載器沒(méi)有加載到某個(gè)類(lèi)的話,就會(huì)通過(guò)LaunchedURLClassLoader這個(gè)加載器來(lái)加載類(lèi)。這個(gè)加載器會(huì)從Boot-INF下面的class目錄和lib目錄下加載類(lèi)。
ClassLoader classLoader = createClassLoader(getClassPathArchives());
//這個(gè)方法會(huì)讀取jar描述文件中的Start-Class屬性,然后通過(guò)反射調(diào)用到這個(gè)類(lèi)的main方法。
launch(args, getMainClass(), classLoader);
}
簡(jiǎn)單總結(jié)
- Spring Boot 可執(zhí)行 Jar 包的入口點(diǎn)是 JarLauncher 的 main 方法;
- 這個(gè)方法的執(zhí)行邏輯是先創(chuàng)建一個(gè) LaunchedURLClassLoader,這個(gè)加載器加載類(lèi)的邏輯是:先判斷根類(lèi)加載器和擴(kuò)展類(lèi)加載器能否加載到某個(gè)類(lèi),如果都加載不到就從 Boot-INF 下面的 class 和 lib 目錄下去加載;
- 讀取Start-Class屬性,通過(guò)反射機(jī)制調(diào)用啟動(dòng)類(lèi)的 main 方法,這樣就順利調(diào)用到我們開(kāi)發(fā)的 Spring Boot 主啟動(dòng)類(lèi)的 main 方法了。
遠(yuǎn)程調(diào)試
這邊介紹個(gè)調(diào)試 JarLauncher 啟動(dòng)的小技巧:IDEA 遠(yuǎn)程調(diào)試。
step1:我們以下面的方式啟動(dòng)我們的 Spring Boot 應(yīng)用
java -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=y -jar App.jar
step2:在 idea 中進(jìn)行如下配置

然后點(diǎn)擊下面的執(zhí)行按鈕執(zhí)行即可:

以上就是詳解SpringBoot可執(zhí)行Jar包運(yùn)行原理的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Jar包運(yùn)行的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
@RequestBody獲取不到參數(shù)的問(wèn)題
這篇文章主要介紹了@RequestBody獲取不到參數(shù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
Java中的CyclicBarrier循環(huán)柵欄解析
這篇文章主要介紹了Java中的CyclicBarrier循環(huán)柵欄解析,從字面上的意思可以知道,這個(gè)類(lèi)的中文意思是"循環(huán)柵欄",大概的意思就是一個(gè)可循環(huán)利用的屏障,它的作用就是會(huì)讓所有線程都等待完成后才會(huì)繼續(xù)下一步行動(dòng),需要的朋友可以參考下2023-12-12
Java使用synchronized實(shí)現(xiàn)互斥鎖功能示例
這篇文章主要介紹了Java使用synchronized實(shí)現(xiàn)互斥鎖功能,結(jié)合實(shí)例形式分析了Java使用synchronized互斥鎖功能簡(jiǎn)單實(shí)現(xiàn)方法與操作技巧,需要的朋友可以參考下2020-05-05
簡(jiǎn)單解析execute和submit有什么區(qū)別
這篇文章主要介紹了簡(jiǎn)單解析execute和submit有什么區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
springboot項(xiàng)目啟動(dòng)慢的問(wèn)題排查方式
這篇文章主要介紹了springboot項(xiàng)目啟動(dòng)慢的問(wèn)題排查方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
MyBatis中的ResultMap的association和collection標(biāo)簽詳解
這篇文章主要介紹了MyBatis中的ResultMap的association和collection標(biāo)簽詳解,主要包括association標(biāo)簽常用參數(shù)及id & result標(biāo)簽參數(shù)詳解,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10
基于SpringAop中JoinPoint對(duì)象的使用說(shuō)明
這篇文章主要介紹了基于SpringAop中JoinPoint對(duì)象的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java利用EasyExcel實(shí)現(xiàn)導(dǎo)出導(dǎo)入功能的示例代碼
EasyExcel是一個(gè)基于Java的、快速、簡(jiǎn)潔、解決大文件內(nèi)存溢出的Excel處理工具。本文廢話不多說(shuō),直接上手試試,用代碼試試EasyExcel是否真的那么好用2022-11-11

