SpringBoot應(yīng)用能直接運(yùn)行java -jar的原因分析
首先明確一點(diǎn),普通jar包是不能直接運(yùn)行的,比如工具類(lèi)jar
要能運(yùn)行,至少得要一個(gè)main函數(shù)作為入口吧?
SpringBoot應(yīng)用確實(shí)有個(gè)main函數(shù),那么問(wèn)題來(lái)了,java -jar是怎么找到這個(gè)main函數(shù)運(yùn)行的?
先說(shuō)答案
是因?yàn)橐肓藄pring-boot-maven-plugin插件
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin>
不信?
現(xiàn)在不使用這個(gè)插件,將SpringBoot應(yīng)用打個(gè)jar包
target目錄產(chǎn)出文件如下
注意此時(shí)的jar體積為3202KB,內(nèi)容只包含了項(xiàng)目中的代碼和resources下的文件
嘗試java -jar運(yùn)行,報(bào)錯(cuò)沒(méi)有主清單屬性
這是把spring-boot-maven-plugin插件加上,再次打包
target目錄如下
jar包體積變大了!另外多出一個(gè)jar.origin,大小和之前jar包的一樣
當(dāng)然我們只需要關(guān)系jar即可
查看jar包中的內(nèi)容,不僅包含了自己寫(xiě)的類(lèi)(classes),還將依賴的第三方j(luò)ar包全部裝了進(jìn)來(lái)(lib),這種jar被稱為fat jar
這時(shí)使用java -jar命令,成功運(yùn)行!
按照常規(guī)思路,一定是要找到main方法所在的這個(gè)類(lèi),然后去運(yùn)行里面的main方法
其實(shí),當(dāng)執(zhí)行java -jar時(shí),會(huì)自動(dòng)去找一個(gè)叫MANIFEST.MF的文件,然后根據(jù)其中的Main-Class找到入口類(lèi),并執(zhí)行其中的main方法
而SpringBoot的jar包的這個(gè)文件,就是spring-boot-maven-plugin這個(gè)插件生成的
這個(gè)文件中的內(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居然不是我們自己寫(xiě)的那個(gè)類(lèi)
而是org.springframework.boot.loader.JarLauncher
想要查看這個(gè)類(lèi),先引入以下依賴
<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)建一個(gè)自定義的類(lèi)加載器
LaunchedURLClassLoader
- 使用這個(gè)自定義的ClassLoader去加載我們自己寫(xiě)的main方法類(lèi),這個(gè)類(lèi)由MANIFEST.MF中Start-Class定義
- 反射獲取main方法,然后執(zhí)行
以上就是SpringBoot應(yīng)用能直接運(yùn)行java -jar的原因分析的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot直接運(yùn)行java -jar的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot 結(jié)合 aop 實(shí)現(xiàn)讀寫(xiě)分離
這篇文章主要介紹了Spring Boot 結(jié)合 aop 實(shí)現(xiàn)讀寫(xiě)分離的示例,幫助大家更好的理解和使用Spring Boot框架,感興趣的朋友可以了解下2020-11-11Springboot項(xiàng)目通過(guò)redis實(shí)現(xiàn)接口的冪等性
這篇文章主要為大家介紹了Springboot項(xiàng)目通過(guò)redis實(shí)現(xiàn)接口的冪等性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12SpringCloud Gateway使用redis實(shí)現(xiàn)動(dòng)態(tài)路由的方法
這篇文章主要介紹了SpringCloud Gateway使用redis實(shí)現(xiàn)動(dòng)態(tài)路由的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Java并發(fā)編程之性能、擴(kuò)展性和響應(yīng)
這篇文章主要介紹了Java并發(fā)編程之性能、擴(kuò)展性和響應(yīng),重點(diǎn)在于多線程應(yīng)用程序的性能問(wèn)題,給性能和擴(kuò)展性下一個(gè)定義,然后再仔細(xì)學(xué)習(xí)一下Amdahl法則,感興趣的小伙伴們可以參考一下2016-02-02Java壓縮文件工具類(lèi)ZipUtil使用方法代碼示例
這篇文章主要介紹了Java壓縮文件工具類(lèi)ZipUtil使用方法代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11java微信企業(yè)號(hào)開(kāi)發(fā)之發(fā)送消息(文本、圖片、語(yǔ)音)
這篇文章主要為大家詳細(xì)介紹了java微信企業(yè)號(hào)開(kāi)發(fā)之發(fā)送消息,發(fā)送類(lèi)型包括文本、圖片、語(yǔ)音,感興趣的小伙伴們可以參考一下2016-06-06SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之詳解易寶支付的流程
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第21戰(zhàn)之易寶支付的流程,感興趣的小伙伴們可以參考一下2016-06-06