一、引言
Java開發中我們使用最多的便是spring框架,比如springboot應用。微服務模式下,每個服務都是一個springboot應用,都會被打包成一個可執行jar包。那么我們有多少人嘗試去了解過這個可執行jar到底是什么?它的結構是什么樣的,我認為大部分人是沒有關注過這個的,今天筆者就通過探索的方式,揭開可執行jar的真面目。
二、打包項目
首先使用IDEA隨便創建一個spring web項目,打包一下看下target目錄
classes
展開看到如下結構,主要是把我們自己寫的.java文件編譯成的.class文件和一些配置文件.yaml或者.properties,我們常說的classpath路徑,就是這個classes文件下的路徑。
generated-sources
這個一般是用來存放框架或者工具自動生成的一些源碼或者文件的地方,比如注解Lombok等。
generated-test-sources
這個沒什么好說的,用來存放生成一些測試代碼源或者文件的地方
maven-archiver
aven-archiver是Maven內部使用的一個組件,它屬于org.apache.maven.archiver包,主要職責在于幫助Maven插件(如maven-jar-plugin, maven-war-plugin等)創建和管理歸檔文件(例如JAR, WAR, EAR等)。它處理諸如設置歸檔的元數據(如Manifest文件內容)、收集和歸檔項目資源和編譯后的類文件等工作。
maven-status
maven-status是Maven在構建過程中創建的一個臨時目錄,用于存儲構建期間的中間狀態信息。這個目錄的內容主要是由Maven的maven-build-number-plugin或maven-checkstyle-plugin等插件生成的,特別是那些需要跟蹤文件狀態的插件。
surefire-reports
surefire-reports是Maven項目在執行單元測試時生成的測試報告目錄
test-classes
這個就是測試類的生成目錄
以上就是maven打包后的目錄解析說明,接下來的這兩個單獨的文件是重點
三、可執行jar包
首先看這個.jar.original后綴的文件,
進入target目錄下,用360解壓縮解壓下original文件解壓到自己新建的original文件夾下
使用IDEA查看,看到文件結構如下
這個文件很小只有7kb,主要是應用的本地資源,并不包含第三方依賴。
再看.jar結尾的文件,這個就是我們打包好的可執行jar包,同樣的解壓到創建的jarExcutable文件中
在IDEA中查看結構如下
使用terminal控制臺,輸入tree
這個文件結構相對來說就比較復雜了,解釋下關鍵部分
- BOOT-INF/classes:存放的是應用編譯后的class文件
- BOOT-INF/lib:這個存放的是我們引用的所有第三方jar包依賴
- META-INF/:存放應用相關的元信息
- org/:存放的是springboot相關的class文件
這個和標準的java EE web應用很相似,在java EE web應用中class文件放在WEB-INF/classes下,依賴的jar包就放在WEB-INF/lib下,二者很相似,其實spring很多東西是在java EE web基礎上發展而來。
java -jar yourapplicationName.jar命令可以啟動我們的jar包,那么為什么能啟動呢?打開這個MANIFEST.MF文件內容
內容如下
這個JarLauncher
就是可執行JAR文件啟動器,是由以下插件spring-boot-maven-plugin
追加進去的,JarLauncher是專門裝載引導類(啟動類)的
pom文件中引入如下依賴(實際開發不需要引入,這里是為了看源碼)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-loader</artifactId>
</dependency>
JarLauncher源碼如下
/** Copyright 2012-2023 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package org.springframework.boot.loader.launch;/*** {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are* included inside a {@code /BOOT-INF/lib} directory and that application classes are* included inside a {@code /BOOT-INF/classes} directory.** @author Phillip Webb* @author Andy Wilkinson* @author Madhura Bhave* @author Scott Frederick* @since 3.2.0*/
public class JarLauncher extends ExecutableArchiveLauncher {public JarLauncher() throws Exception {}protected JarLauncher(Archive archive) throws Exception {super(archive);}@Overrideprotected boolean isIncludedOnClassPath(Archive.Entry entry) {return isLibraryFileOrClassesDirectory(entry);}@Overrideprotected String getEntryPathPrefix() {return "BOOT-INF/";}static boolean isLibraryFileOrClassesDirectory(Archive.Entry entry) {String name = entry.name();if (entry.isDirectory()) {return name.equals("BOOT-INF/classes/");}return name.startsWith("BOOT-INF/lib/");}public static void main(String[] args) throws Exception {new JarLauncher().launch(args);}}
其中的BOOT-INF/lib/和BOOT-INF/classes/對應我們解壓jar包后的相關文件目錄,說明JarLauncher 會從中加載文件