詳解springboot可執行jar包運行原理
打可執行 jar 包
將 spring boot 應用打成可執行 ja r包很容易,只需要在 pom 中加上一個 spring boot 提供的插件,然后在執行mvn package即可。
<build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> </plugin> </plugins> </build>
注意:
如果你的項目沒有繼承spring-boot-starter-parent這個pom,你需要做如下配置,將目標綁定到repackage。
<plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin>
關于這個插件的詳細使用,可以參考官網
運行完mvn package后,我們會在 target 目錄下看到兩個 jar 文件。myproject-0.0.1-snapshot.jar 和 myproject-0.0.1-snapshot.jar.original。第一個 jar 文件就是我們應用的可執行 jar 包,第二個 jar 文件是應用原始的 jar 包。
可執行 jar 包內部結構
將打出來的可執行 jar 解壓開我們能看到下面的結構:
可執行 jar 目錄結構
├─boot-inf
│ ├─classes
│ └─lib
├─meta-inf
│ ├─maven
│ ├─app.properties
│ ├─manifest.mf
└─org
└─springframework
└─boot
└─loader
├─archive
├─data
├─jar
└─util
我們先來重點關注兩個地方:meta-inf 下面的 jar 包描述文件和 boot-inf 這個目錄。
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
在上面我們看到一個熟悉的配置main-class: org.springframework.boot.loader.jarlauncher。我們大概能猜到這個類是整個系統的入口。
再看下 boot-inf 這個目錄下面,我們會發現里面是我們項目打出來的 class 文件和項目依賴的 jar 包。看到這里,你可能已經猜到 spring boot 是怎么啟動項目的了。
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 { //項目入口,重點在launch這個方法中 new jarlauncher().launch(args); } }
//launch方法 protected void launch(string[] args) throws exception { jarfile.registerurlprotocolhandler(); //創建launchedurlclassloader。如果根類加載器和擴展類加載器沒有加載到某個類的話,就會通過launchedurlclassloader這個加載器來加載類。這個加載器會從boot-inf下面的class目錄和lib目錄下加載類。 classloader classloader = createclassloader(getclasspatharchives()); //這個方法會讀取jar描述文件中的start-class屬性,然后通過反射調用到這個類的main方法。 launch(args, getmainclass(), classloader); }
簡單總結
- spring boot 可執行 jar 包的入口點是 jarlauncher 的 main 方法;
- 這個方法的執行邏輯是先創建一個 launchedurlclassloader,這個加載器加載類的邏輯是:先判斷根類加載器和擴展類加載器能否加載到某個類,如果都加載不到就從 boot-inf 下面的 class 和 lib 目錄下去加載;
- 讀取start-class屬性,通過反射機制調用啟動類的 main 方法,這樣就順利調用到我們開發的 spring boot 主啟動類的 main 方法了。
遠程調試
這邊介紹個調試 jarlauncher 啟動的小技巧:idea 遠程調試。
step1:我們以下面的方式啟動我們的 spring boot 應用
java -xdebug -xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=y -jar app.jar
step2:在 idea 中進行如下配置
然后點擊下面的執行按鈕執行即可:
以上就是詳解springboot可執行jar包運行原理的詳細內容,更多關于springboot jar包運行的資料請關注碩編程其它相關文章!