詳解SpringBoot可執(zhí)行Jar包運(yùn)行原理

詳解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)目沒有繼承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)

將打出來的可執(zhí)行 jar 解壓開我們能看到下面的結(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

我們先來重點(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è)類是整個(gè)系統(tǒng)的入口。

再看下 boot-inf 這個(gè)目錄下面,我們會(huì)發(fā)現(xiàn)里面是我們項(xiàng)目打出來的 class 文件和項(xiàng)目依賴的 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。如果根類加載器和擴(kuò)展類加載器沒有加載到某個(gè)類的話,就會(huì)通過launchedurlclassloader這個(gè)加載器來加載類。這個(gè)加載器會(huì)從boot-inf下面的class目錄和lib目錄下加載類。
  classloader classloader = createclassloader(getclasspatharchives());
  //這個(gè)方法會(huì)讀取jar描述文件中的start-class屬性,然后通過反射調(diào)用到這個(gè)類的main方法。
  launch(args, getmainclass(), classloader);
}

 

簡(jiǎn)單總結(jié)

  • spring boot 可執(zhí)行 jar 包的入口點(diǎn)是 jarlauncher 的 main 方法;
  • 這個(gè)方法的執(zhí)行邏輯是先創(chuàng)建一個(gè) launchedurlclassloader,這個(gè)加載器加載類的邏輯是:先判斷根類加載器和擴(kuò)展類加載器能否加載到某個(gè)類,如果都加載不到就從 boot-inf 下面的 class 和 lib 目錄下去加載;
  • 讀取start-class屬性,通過反射機(jī)制調(diào)用啟動(dòng)類的 main 方法,這樣就順利調(diào)用到我們開發(fā)的 spring boot 主啟動(dòng)類的 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)文章!

下一節(jié):詳解java中如何定義和訪問靜態(tài)字段和方法

java編程技術(shù)

相關(guān)文章
亚洲国产精品第一区二区,久久免费视频77,99V久久综合狠狠综合久久,国产免费久久九九免费视频