SpringBoot應用能直接運行java -jar的原因分析
首先明確一點,普通jar包是不能直接運行的,比如工具類jar
要能運行,至少得要一個main函數(shù)作為入口吧?
SpringBoot應用確實有個main函數(shù),那么問題來了,java -jar是怎么找到這個main函數(shù)運行的?
先說答案
是因為引入了spring-boot-maven-plugin插件
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
不信?
現(xiàn)在不使用這個插件,將SpringBoot應用打個jar包
target目錄產(chǎn)出文件如下

注意此時的jar體積為3202KB,內(nèi)容只包含了項目中的代碼和resources下的文件

嘗試java -jar運行,報錯沒有主清單屬性

這是把spring-boot-maven-plugin插件加上,再次打包
target目錄如下

jar包體積變大了!另外多出一個jar.origin,大小和之前jar包的一樣
當然我們只需要關系jar即可
查看jar包中的內(nèi)容,不僅包含了自己寫的類(classes),還將依賴的第三方jar包全部裝了進來(lib),這種jar被稱為fat jar

這時使用java -jar命令,成功運行!

按照常規(guī)思路,一定是要找到main方法所在的這個類,然后去運行里面的main方法
其實,當執(zhí)行java -jar時,會自動去找一個叫MANIFEST.MF的文件,然后根據(jù)其中的Main-Class找到入口類,并執(zhí)行其中的main方法

而SpringBoot的jar包的這個文件,就是spring-boot-maven-plugin這個插件生成的
這個文件中的內(nèi)容如下
Manifest-Version: 1.0 Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx Archiver-Version: Plexus Archiver Built-By: yimin Spring-Boot-Layers-Index: BOOT-INF/layers.idx Start-Class: com.example.k8sdemo.K8sDemoApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Version: 2.6.13 Created-By: Apache Maven 3.8.8 Build-Jdk: 1.8.0_392 Main-Class: org.springframework.boot.loader.JarLauncher
好家伙,Main-Class居然不是我們自己寫的那個類
而是org.springframework.boot.loader.JarLauncher
想要查看這個類,先引入以下依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
</dependency>
JarLauncher的main函數(shù)以及方法調(diào)用如下
public static void main(String[] args) throws Exception {
new JarLauncher().launch(args);
}
protected void launch(String[] args) throws Exception {
if (!isExploded()) {
JarFile.registerUrlProtocolHandler();
}
ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator());
String jarMode = System.getProperty("jarmode");
String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass();
launch(args, launchClass, classLoader);
}
@Override
protected String getMainClass() throws Exception {
String mainClass = getProperty(MAIN, "Start-Class");
if (mainClass == null) {
throw new IllegalStateException("No '" + MAIN + "' or 'Start-Class' specified");
}
return mainClass;
}
protected void launch(String[] args, String launchClass, ClassLoader classLoader) throws Exception {
Thread.currentThread().setContextClassLoader(classLoader);
createMainMethodRunner(launchClass, args, classLoader).run();
}
protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
return new MainMethodRunner(mainClass, args);
}
public void run() throws Exception {
Class<?> mainClass = Class.forName(this.mainClassName, false, Thread.currentThread().getContextClassLoader());
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.setAccessible(true);
mainMethod.invoke(null, new Object[] { this.args });
}
總結(jié)一下就是
- 創(chuàng)建一個自定義的類加載器
LaunchedURLClassLoader - 使用這個自定義的ClassLoader去加載我們自己寫的main方法類,這個類由MANIFEST.MF中Start-Class定義
- 反射獲取main方法,然后執(zhí)行
以上就是SpringBoot應用能直接運行java -jar的原因分析的詳細內(nèi)容,更多關于SpringBoot直接運行java -jar的資料請關注腳本之家其它相關文章!
相關文章
Java Long轉(zhuǎn)JSON出現(xiàn)精度丟失問題及解決
Java Long類型轉(zhuǎn)JSON時可能因JSON的通用數(shù)字類型不指定位數(shù)大小及JavaScript整數(shù)表達精度限制導致精度丟失,解決方法包括在Java對象中為Long類型字段添加@JsonFormat(shape=JsonFormat.Shape.STRING)注解,或在Spring框架中配置ObjectMapper以全局序列化行為2025-12-12
Jmeter多臺機器并發(fā)請求實現(xiàn)壓力性能測試
這篇文章主要介紹了Jmeter多臺機器并發(fā)請求實現(xiàn)壓力性能測試,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-10-10
spring異步service中處理線程數(shù)限制詳解
這篇文章主要給大家介紹了關于spring異步service中處理線程數(shù)限制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用spring具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-09-09

