Spring Boot 可執(zhí)行 jar 可執(zhí)行 war 結(jié)構(gòu)

原文地址 https://docs.spring.io/spring-boot/docs/1.5.19.BUILD-SNAPSHOT/reference/htmlsingle/#executable-jar

Spring引導(dǎo)加載程序模塊允許Spring引導(dǎo)支持可執(zhí)行jar和war文件。如果您正在使用Maven或Gradle插件,那么可執(zhí)行jar將自動生成,您通常不需要知道它們?nèi)绾喂ぷ鞯募?xì)節(jié)。

如果您需要從不同的構(gòu)建系統(tǒng)創(chuàng)建可執(zhí)行jar,或者您只是對底層技術(shù)感興趣,那么本節(jié)將提供一些背景知識。

E.1嵌套的jar

Java沒有提供任何加載嵌套的jar文件(即包含在jar中的jar文件)的標(biāo)準(zhǔn)方法。如果您希望分發(fā)一個自包含的應(yīng)用程序,您可以只從命令行運行該應(yīng)用程序,而不需要解壓縮,那么這可能會有問題。
為了解決這個問題,許多開發(fā)人員使用“shaded”jar。shaded jar只是將所有jar中的所有類打包到一個“uber jar”中。shaded jar的問題是,很難看到在應(yīng)用程序中實際使用的庫。如果在多個jar中使用相同的文件名(但內(nèi)容不同),也會出現(xiàn)問題。Spring Boot采用了一種不同的方法,允許您直接嵌套jar。

E.1.1 可執(zhí)行jar文件結(jié)構(gòu)

Spring引導(dǎo)加載程序兼容的jar文件的結(jié)構(gòu)應(yīng)該如下所示:

example.jar
 |
 +-META-INF
 |  +-MANIFEST.MF
 +-org
 |  +-springframework
 |     +-boot
 |        +-loader
 |           +-<spring boot loader classes>
 +-BOOT-INF
    +-classes
    |  +-mycompany
    |     +-project
    |        +-YourClasses.class
    +-lib
       +-dependency1.jar
       +-dependency2.jar

應(yīng)用程序類應(yīng)該放在一個嵌套的BOOT-INF/classes目錄中. 依賴項應(yīng)該放在一個嵌套的BOOT-INF/lib目錄中。

E.1.2 可執(zhí)行的war文件結(jié)構(gòu)

兼容Spring Boot Loader的war文件的結(jié)構(gòu)應(yīng)該是這樣的:

example.war
 |
 +-META-INF
 |  +-MANIFEST.MF
 +-org
 |  +-springframework
 |     +-boot
 |        +-loader
 |           +-<spring boot loader classes>
 +-WEB-INF
    +-classes
    |  +-com
    |     +-mycompany
    |        +-project
    |           +-YourClasses.class
    +-lib
    |  +-dependency1.jar
    |  +-dependency2.jar
    +-lib-provided
       +-servlet-api.jar
       +-dependency3.jar

依賴項應(yīng)該放在嵌套的WEB-INF/lib目錄中。嵌入式運行時需要但部署到傳統(tǒng)web容器時不需要的任何依賴項都應(yīng)該放在WEB-INF/lib-provide中。

E.2 Spring Boot’s “JarFile” class

用于支持加載嵌套jar的核心類是org.springframework.boot.loader.jar.JarFile。它允許您加載標(biāo)準(zhǔn)jar文件或嵌套的jar文件。第一次加載時,每個JarEntry的位置都被映射成外部jar的文件偏移量

myapp.jar
+-------------------+-------------------------+
| /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |
|+-----------------+||+-----------+----------+|
||     A.class      |||  B.class  |  C.class ||
|+-----------------+||+-----------+----------+|
+-------------------+-------------------------+
 ^                    ^           ^
 0063                 3452        3980

上面的例子展示了A。類可以在myapp.jar中的/BOOT-INF/classes中找到相當(dāng)于myapp.jar的0063文件偏移量的位置。B class 可以在myapp嵌套jar的3452文件偏移量中找到,C class 可以再3980位置找到。

有了這些信息,我們可以通過查找外部jar的適當(dāng)部分來加載特定的嵌套jar。我們不需要解壓歸檔文件,也不需要將所有條目數(shù)據(jù)讀入內(nèi)存。

E.2.1 與標(biāo)準(zhǔn)Java“JarFile”的兼容性

Spring引導(dǎo)加載程序努力保持與現(xiàn)有代碼和庫的兼容性。org.springframework.boot.loader.jar.JarFilejava.util.jar.JarFile的擴(kuò)展。是可替換的。getURL()方法將返回一個URL,該URL打開一個兼容java.net.JarURLConnection的連接,可以與Java的URLClassLoader一起使用。

E.3 啟動可執(zhí)行jar

org.springframework.boot.loader.Launcher 啟動器類是一個特殊的引導(dǎo)類,它用作一個可執(zhí)行jar主入口點。它是jar文件中實際的主類,用于設(shè)置適當(dāng)?shù)?code>URLClassLoader并最終調(diào)用main()方法。

有3個啟動器子類(JarLauncher, WarLauncherPropertiesLauncher)。它們的目的是加載資源(.class文件等)從目錄中的嵌套jar文件或war文件(與類路徑中的顯式文件相反)獲取。在JarLauncherWarLauncher的情況下,嵌套路徑是固定的。JarLauncherBOOT-INF/lib/ ,WarLauncherWEB-INF/lib/和WEB-INF/lib-provide/ 中查找,所以如果您想要更多,只需在這些位置添加額外的jar即可。默認(rèn)情況下,PropertiesLauncher會出現(xiàn)在應(yīng)用程序存檔中的BOOT-INF/lib/中,您可以通過設(shè)置環(huán)境變量LOADER_PATHloader來添加其他位置。

E.3.1 啟動程序清單(Launcher manifest)

您需要指定一個適當(dāng)?shù)膯映绦蜃鳛镸ETA-INF/MANIFEST.MF的主類屬性。應(yīng)該在start類屬性中指定要啟動的實際類(即您編寫的包含main方法的類)。

例如,下面是一個典型的清單。MF為可執(zhí)行jar文件:

Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication

對于war文件,它應(yīng)該是:

Main-Class: org.springframework.boot.loader.WarLauncher
Start-Class: com.mycompany.project.MyApplication

您不需要在清單文件中指定類路徑項,程序會自動查找路徑。

E.3.2 Exploded archives(歸檔文件)

某些PaaS實現(xiàn)可能選擇在運行前解包存檔。例如,你可以運行一個解壓縮檔案,只需啟動適當(dāng)?shù)膯悠?

$ unzip -q myapp.jar
$ java org.springframework.boot.loader.JarLauncher

E.4 PropertiesLauncher特性

PropertiesLauncher has a few special features that can be enabled with external properties (System properties, environment variables, manifest entries or loader.properties).

PropertiesLauncher支持從loader.properties以及(由于歷史原因)application.properties加載屬性。我們建議使用loader.properties,作為對應(yīng)用程序的支持。application.properties已被棄用,將來可能會被刪除。

Key Purpose
loader.path 逗號分隔的類路徑,例如lib、${HOME}/app/lib,類似 javac -classpath
loader.home 用于解析loader.path中的相對路徑。如裝載機(jī)。loader.path=lib ${loader.home}/lib是一個類路徑位置(以及該目錄中的所有jar文件)。也用于定位加載loader.properties。示例/opt/app(默認(rèn)為${user.dir})。
loader.args 主方法的默認(rèn)參數(shù)(以空格分隔)
loader.main 要啟動的主類的名稱,例如com.app.Application
loader.config.name 屬性文件的名稱,例如啟動器(默認(rèn)為加載器)。
loader.config.location 屬性文件的路徑,例如類路徑:loader。屬性(默認(rèn)為loader.properties)。
loader.system 布爾標(biāo)志,指示應(yīng)將所有屬性添加到系統(tǒng)屬性中(默認(rèn)為false)

當(dāng)指定為環(huán)境變量或清單項時,應(yīng)使用以下名稱:

Key Manifest entry Environment variable
loader.path Loader-Path LOADER_PATH
loader.home Loader-Home LOADER_HOME
loader.args Loader-Args LOADER_ARGS
loader.main Start-Class LOADER_MAIN
loader.config.location Loader-Config-Location LOADER_CONFIG_LOCATION
loader.system Loader-System LOADER_SYSTEM

構(gòu)建插件在構(gòu)建fat jar時自動將Main-Class屬性移動到Start-Class。如果您正在使用它,請使用Main-Class屬性指定要啟動的類的名稱,并省略Start-Class。

loader.properties 先在 loader.home查找 然后在classpath根目錄查找, 最后是classpath:/BOOT-INF/classes 使用存在的第一個位置。
loader.home 只是一個附加屬性文件的目錄位置(覆蓋默認(rèn)值),只要load.config存在。沒有指定位置。
loader.path 可以包含目錄(遞歸掃描jar和zip文件)、歸檔路徑、歸檔文件中掃描jar文件的目錄(例如,“dependensis .jar!/lib”)或通配符模式(默認(rèn)JVM行為)。存檔路徑可以相對于加載器。home,或者文件系統(tǒng)中具有jar:file:前綴的任何地方。
loader.path path(如果為空)默認(rèn)為BOOT-INF/lib(意味著從存檔文件運行的本地目錄或嵌套目錄)。由于這個屬性,當(dāng)沒有提供額外配置時,啟動器的行為與JarLauncher相同。
loader.path 不能用于配置加載程序的位置。屬性(用于搜索后者的類路徑是啟動PropertiesLauncher時的JVM類路徑)。
占位符替換是在使用前從系統(tǒng)和環(huán)境變量以及所有值上的屬性文件本身進(jìn)行的。
屬性的搜索順序是env vars、系統(tǒng)屬性和loader(在多個位置查找是有意義的)。屬性,分解的存檔清單,存檔清單。

E.5 可執(zhí)行jar的限制

在使用Spring引導(dǎo)加載程序打包的應(yīng)用程序時,需要考慮許多限制。

E.5.1 Zip實體壓縮(Zip entry compression)

嵌套實體 ZipEntry 必須使用 ZipEntry.STORED 方法,這是必需的,以便我們可以直接查找嵌套jar中的各個內(nèi)容。嵌套jar文件本身的內(nèi)容仍然可以壓縮,外部jar中的其他entries也可以壓縮。

E.5.2 System ClassLoader

啟動的應(yīng)用程序在加載類時應(yīng)該使用Thread.getContextClassLoader()(默認(rèn)情況下,大多數(shù)庫和框架都會這樣做)。通過ClassLoader.getSystemClassLoader()加載嵌套的jar類將會失敗。請注意java.util.Logging總是使用系統(tǒng)類加載器,因此您應(yīng)該考慮不同的日志實現(xiàn)。

E.6 可選的fat jar 替代方案

如果上述限制意味著您不能使用Spring引導(dǎo)加載程序,可以考慮以下替代方案:

  • Maven Shade Plugin
  • JarClassLoader
  • OneJar
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容