spring boot 包結構
Nested JARs
Java沒有提供任何標準的方法來加載嵌套的jar文件(即本身包含在jar中的jar文件)。如果需要分發自包含的應用程序,而該應用程序可以從命令行運行而無需解壓縮,則這可能會有問題。
爲了解決這個問題,許多開發人員使用“陰影”jar。一個陰影jar將所有類從所有jar打包成一個“uber jar”。這些jar的問題是,很難看到應用程序中實際存在哪些庫,如果在多個jar中使用相同的文件名(但內容不同),也會有問題。
Spring Boot採用了一種不同的方法,允許您直接嵌套jar。
The Executable Jar File Structure
與Spring Boot Loader兼容的jar文件的結構應如下所示:
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
應用程序類應該放在嵌套的BOOT-INF/classes目錄中。依賴項應該放在嵌套的BOOT-INF/lib目錄中。
The Executable War File Structure
與Spring Boot Loader兼容的war文件的結構應如下:
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
依賴項應該放在嵌套的WEB-INF/lib目錄中。運行嵌入式時需要但部署到傳統web容器時不需要的任何依賴項都應該放在WEB-INF/lib-provided中。
Spring Boot’s “JarFile” Class
用於支持加載嵌套jar的核心類是org.springframework.boot.loader.jar.JarFile。它允許您從標準jar文件或嵌套的子jar數據加載jar內容。第一次加載時,每個JarEntry的位置都映射到外部jar的物理文件偏移量,如下例所示:
myapp.jar
+-------------------+-------------------------+
| /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar |
|+-----------------+||+-----------+----------+|
|| A.class ||| B.class | C.class ||
|+-----------------+||+-----------+----------+|
+-------------------+-------------------------+
^ ^ ^
0063 3452 3980
前面的示例顯示瞭如何在位於0063位置的myapp.jar中的/BOOT-INF/classes中找到A.class。嵌套jar中的B.class實際上可以在位置3452的myapp.jar中找到,而C.class位於位置3980。
有了這些信息,我們可以通過尋找外部jar的適當部分來加載特定的嵌套條目。我們不需要解壓縮存檔文件,也不需要將所有條目數據讀入內存。
Compatibility with the Standard Java “JarFile”
Spring引導加載程序試圖保持與現有代碼和庫的兼容性。org.springframework.boot.loader.jar.JarFile 從java.util.jar.JarFile 擴展而來,應該作爲一個替換項。getURL()方法返回一個URL,該URL打開與java.net.JarURLConnection兼容的連接,並可與java的URLClassLoader一起使用。
Launching Executable Jars
boot.loader.Launcher類是一個特殊的引導類,用作可執行jar的主要入口點。它是jar文件中的實際主類,用於設置適當的URLClassLoader並最終調用你的main()方法。
有三個子類(JarLauncher、WarLauncher和PropertiesLauncher)。它們的目的是從目錄中的嵌套jar文件或war文件(而不是明確的類路徑上)加載資源(.class文件等)。對於JarLauncher和WarLauncher嵌套路徑是固定的。JarLauncher looks in BOOT-INF/lib/, and WarLauncher looks in WEB-INF/lib/and WEB-INF/lib-provided/.如果需要更多,可以在這些位置添加額外的jar。默認情況下,PropertiesLauncher在應用程序歸檔文件的BOOT-INF/lib/中查找。您可以通過在loader.properties中設置名爲LOADER_PATH或LOADER.PATH的環境變量(這是以逗號分隔的存檔中的目錄、存檔或目錄列表)來添加其他位置。
Launcher Manifest
您需要指定適當的啓動程序作爲META-INF/MANIFEST.MF的主類屬性。要啓動的實際類(即包含main方法的類)應在Start-class屬性中指定。
以下示例顯示可執行jar文件的典型MANIFEST.MF:
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication
對於war文件,如下所示:
Main-Class: org.springframework.boot.loader.WarLauncher
Start-Class: com.mycompany.project.MyApplication
不需要在清單文件中指定類路徑項。類路徑是從嵌套的jar中推導出來的。
PropertiesLauncher Features
PropertiesLauncher有一些特殊功能,可以使用外部屬性(系統屬性、環境變量、清單條目或loader.properties)啓用。下表描述了這些屬性:
loader.path |
Comma-separated Classpath, such as lib,${HOME}/app/lib. Earlier entries take precedence, like a regular -classpath on the javac command line. |
loader.home |
Used to resolve relative paths in loader.path. For example, given loader.path=lib, then ${loader.home}/lib is a classpath location (along with all jar files in that directory). This property is also used to locate a loader.properties file, as in the following example /opt/app It defaults to ${user.dir}. |
loader.args |
Default arguments for the main method (space separated). |
loader.main |
Name of main class to launch (for example, com.app.Application). |
loader.config.name |
Name of properties file (for example, launcher). It defaults to loader. |
loader.config.location |
Path to properties file (for example, classpath:loader.properties). It defaults to loader.properties. |
loader.system |
Boolean flag to indicate that all properties should be added to System properties. It defaults to false. |
當指定爲環境變量或清單項時,應使用以下名稱:
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 |
構建插件會在構建胖jar時自動將主類屬性移動到Start Class。如果使用該屬性,請使用Main class屬性指定要啓動的類的名稱。
以下規則適用於使用PropertiesLauncher:
loader.properties:
在loader.home中搜索,然後在類路徑的根目錄中classpath搜索,然後在類路徑中搜索/BOOT-INF/classes。使用具有該名稱的文件的第一個位置。
loader.home:
僅當未指定loader.config.location時,它纔是附加屬性文件(覆蓋默認值)的目錄位置。
loader.path:
可以包含目錄(遞歸掃描jar和zip文件)、存檔路徑、存檔中掃描jar文件的目錄(例如dependencies.jar!)!/或通配符模式(用於默認的JVM行爲)。存檔路徑可以相對於loader.home或文件系統中帶有jar:file:prefix的任何位置。
loader.path:
(如果爲空)默認爲BOOT-INF/lib(如果從存檔運行,則表示本地目錄或嵌套目錄)。因此,當沒有提供額外的配置時,PropertiesLauncher的行爲與JarLauncher相同。
loader.path:
無法用於配置loader.properties的位置(啓動PropertiesLauncher時用於搜索後者的類路徑是JVM類路徑)。
佔位符替換是在使用前從系統和環境變量以及所有值上的屬性文件本身完成的。
屬性properties 的搜索順序(在多個地方查找是有意義的)是環境變量、系統屬性、loader.properties、分解的存檔清單和存檔清單。
Executable Jar Restrictions
在使用Spring Boot Loader打包應用程序時,需要考慮以下限制:
壓縮:必須使用ZipEntry.STORED方法保存嵌套JAR的ZipEntry。這是必需的,這樣我們就可以直接查找嵌套JAR中的單個內容。嵌套JAR文件本身的內容仍然可以壓縮,外部JAR中的任何其他條目也可以壓縮。
SystemclassLoader:啓動的應用程序在加載類時應該使用Thread.getContextClassLoader()(默認情況下大多數庫和框架都這樣做)。試圖用ClassLoader.getSystemClassLoader()加載嵌套的JAR類失敗。 java.util.Logging 總是使用系統類加載器。因此,您應該考慮使用不同的日誌記錄實現。