这些spring-boot-loader
模块使Spring Boot支持可执行的jar和war文件。如果您使用Maven插件或Gradle插件,则会自动生成可执行jar,通常不需要了解其工作方式的详细信息。
如果您需要从其他构建系统创建可执行jar,或者您只是对基础技术感到好奇,则本附录提供了一些背景知识。
1.嵌套的JAR
Java没有提供任何标准的方式来加载嵌套的jar文件(即,它们本身包含在jar中的jar文件)。如果您需要分发一个自包含的应用程序,而该应用程序可以从命令行运行而无需解压缩,则可能会出现问题。
为了解决这个问题,许多开发人员使用“阴影”罐子。一个有阴影的jar将所有jar中的所有类打包到一个“超级jar”中。带阴影的jar的问题在于,很难查看应用程序中实际包含哪些库。如果在多个jar中使用了相同的文件名(但内容不同),也可能会产生问题。Spring Boot采用了另一种方法,实际上允许您直接嵌套jar。
1.1。可执行的Jar文件结构
与Spring Boot Loader兼容的jar文件的结构应采用以下方式:
example.jar
|
+ -META-INF
| +-清单文件
+组织
| + -springframework
| +启动
| +装载机
| +-
+引导-INF
+类
| +-我的公司
| +项目
| + -YourClasses.class
+库
+ -dependency1.jar
+ -dependency2.jar
应用程序类应放置在嵌套BOOT-INF/classes
目录中。依赖项应放在嵌套BOOT-INF/lib
目录中。
1.2。可执行战争文件结构
与Spring Boot Loader兼容的war文件的结构应采用以下方式:
example.war
|
+ -META-INF
| +-清单文件
+组织
| + -springframework
| +启动
| +装载机
| +-
+-网络-INF
+类
| + -com
| +-我的公司
| +项目
| + -YourClasses.class
+库
| + -dependency1.jar
| + -dependency2.jar
+ -lib提供
+ -servlet-api.jar
+ -dependency3.jar
依赖项应放在嵌套WEB-INF/lib
目录中。在运行嵌入式程序时需要但在部署到传统Web容器时不需要的任何依赖项都应放在中WEB-INF/lib-provided
。
1.3。索引文件
兼容Spring Boot Loader的jar和war档案可以在BOOT-INF/
目录下包含其他索引文件。一个classpath.idx
可以提供两个罐子和战争文件,并提供了排序,以罐子应该加入到classpath中。该layers.idx
文件只能用于jar,它允许将jar分为逻辑层以创建Docker / OCI映像。
索引文件遵循YAML兼容语法,以便可以由第三方工具轻松解析。但是,这些文件在内部没有作为YAML进行解析,因此必须按照以下所述的格式编写,才能使用。
1.4。类路径索引
可以在中提供类路径索引文件BOOT-INF/classpath.idx
。它提供了jar名称(包括目录)的列表,其顺序为应将其添加到类路径中。每行必须以破折号("-·"
)开头,并且名称必须用双引号引起来。
例如,给定以下jar:
example.jar
|
+ -META-INF
| + …
+引导-INF
+类
| + …
+库
+ -dependency1.jar
+ -dependency2.jar
索引文件如下所示:
-“ BOOT-INF / lib / dependency2.jar”
-“ BOOT-INF / lib / dependency1.jar”
1.5。层索引
层索引文件可以在中提供BOOT-INF/layers.idx
。它提供了层的列表以及应包含在其中的罐子的各个部分。按照应将其添加到Docker / OCI映像的顺序来编写层。图层名称以带引号的字符串编写,前缀带有短划线空格("-·"
)和冒号(":"
)后缀。图层内容是用引号引起来的字符串形式的文件或目录名称,并以空格短划线("··-·"
)作为前缀。目录名以结尾/
,而文件名则没有。使用目录名称时,意味着该目录内的所有文件都在同一层。
图层索引的典型示例是:
-“依存关系”:
-“ BOOT-INF / lib / dependency1.jar”
-“ BOOT-INF / lib / dependency2.jar”
- “应用”:
-“ BOOT-INF / classes /”
-“ META-INF /”
2. Spring Boot的“ JarFile”类
用于支持加载嵌套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
前面的示例显示了如何在at中A.class
找到。 从嵌套罐子可以实际中可以找到在位置,并且在位置。/BOOT-INF/classes``myapp.jar``0063``B.class``myapp.jar``3452``C.class``3980
有了这些信息,我们可以通过查找外部jar的适当部分来加载特定的嵌套条目。我们不需要解压缩档案,也不需要将所有条目数据读入内存。
2.1。与标准Java“ JarFile”的兼容性
Spring Boot Loader努力保持与现有代码和库的兼容性。 org.springframework.boot.loader.jar.JarFile
扩展java.util.jar.JarFile
并应作为替代产品。该getURL()
方法返回URL
,它打开java.net.JarURLConnection
与Java兼容并可以与Java一起使用的连接URLClassLoader
。
3.启动可执行jar
该org.springframework.boot.loader.Launcher
班是作为一个可执行的JAR的主入口点一个特殊的启动类。它是Main-Class
jar文件中的实际值,用于设置适当URLClassLoader
的main()
方法并最终调用您的方法。
有三个发射子类(JarLauncher
,WarLauncher
,和PropertiesLauncher
)。它们的目的是.class
从目录中的嵌套jar文件或war文件(而不是在类路径中显式的文件)加载资源(文件等)。在的情况下JarLauncher
和WarLauncher
,嵌套路径是固定的。 JarLauncher
看着BOOT-INF/lib/
,WarLauncher
看着WEB-INF/lib/
和WEB-INF/lib-provided/
。如果需要,可以在这些位置添加额外的罐子。默认情况下,PropertiesLauncher
外观在BOOT-INF/lib/
应用程序存档中。您可以通过设置所谓的环境变量添加其他位置LOADER_PATH
或loader.path
在loader.properties
(这是目录,归档或目录的归档中的一个逗号分隔的列表)。
3.1。启动清单
您需要指定一个适当的Launcher
作为的Main-Class
属性META-INF/MANIFEST.MF
。您应该启动的实际类(即包含main
方法的类)应在Start-Class
属性中指定。
以下示例显示了典型MANIFEST.MF
的可执行jar文件:
主类:org.springframework.boot.loader.JarLauncher
开始类别:com.mycompany.project.MyApplication
对于战争文件,将如下所示:
主类:org.springframework.boot.loader.WarLauncher
开始类别:com.mycompany.project.MyApplication
您无需Class-Path 在清单文件中指定条目。类路径是从嵌套的jar中推导出来的。 |
|
---|---|
4. PropertiesLauncher功能
PropertiesLauncher
具有一些可以通过外部属性(系统属性,环境变量,清单条目或loader.properties
)启用的特殊功能。下表描述了这些属性:
钥匙 | 目的 |
---|---|
loader.path |
以逗号分隔的Classpath,例如lib,${HOME}/app/lib 。此前条目优先,像一个普通-classpath 的在javac 命令行。 |
loader.home |
用于解析中的相对路径loader.path 。例如,给定loader.path=lib ,则${loader.home}/lib 是类路径位置(以及该目录中的所有jar文件)。此属性还用于定位loader.properties 文件,如以下示例所示[/opt/app]() ,默认为${user.dir} 。 |
loader.args |
main方法的默认参数(以空格分隔)。 |
loader.main |
要启动的主类的名称(例如com.app.Application )。 |
loader.config.name |
属性文件的名称(例如,launcher )。默认为loader 。 |
loader.config.location |
属性文件的路径(例如classpath:loader.properties )。默认为loader.properties 。 |
loader.system |
布尔型标志,指示应将所有属性添加到系统属性。默认为false 。 |
当指定为环境变量或清单条目时,应使用以下名称:
钥匙 | 清单输入 | 环境变量 |
---|---|---|
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 |
构建插件会自动将Main-Class 属性移动到构建Start-Class 胖罐时。如果使用该名称,请使用Main-Class 属性并省略out来指定要启动的类的名称Start-Class 。 |
|
---|---|
以下规则适用于PropertiesLauncher
:
loader.properties
在中搜索loader.home
,然后在类路径的根目录中搜索,然后在中搜索classpath:/BOOT-INF/classes
。使用具有该名称的文件的第一个位置。loader.home
是仅在loader.config.location
未指定时其他属性文件的目录位置(覆盖默认值)。loader.path
可以包含目录(以递归方式扫描jar和zip文件),归档路径,归档文件中的目录以扫描jar文件(例如dependencies.jar!/lib
)或通配符模式(用于默认的JVM行为)。归档路径可以相对于loader.home
文件系统,也可以在文件系统中的任何位置带有jar:file:
前缀。loader.path
(如果为空)默认为BOOT-INF/lib
(表示本地目录,如果是从存档运行则表示嵌套目录)。因此,PropertiesLauncher
其行为与JarLauncher
未提供其他配置时相同。loader.path
不能用于配置的位置loader.properties
(用于搜索后者的类路径PropertiesLauncher
是启动时的JVM类路径)。- 占位符的替换是使用系统和环境变量以及属性文件本身的所有值进行的,然后再使用。
属性(在多个位置中有意义的查找)的搜索顺序是环境变量,系统属性,
loader.properties
分解的档案清单和档案清单。
5.可执行的Jar限制
使用Spring Boot Loader打包的应用程序时,需要考虑以下限制:
邮编压缩:
ZipEntry
嵌套jar的,必须使用ZipEntry.STORED
方法保存。这是必需的,以便我们可以直接在嵌套jar中查找单个内容。嵌套jar文件本身的内容仍然可以压缩,外部jar中的任何其他条目也可以压缩。系统classLoader:
Thread.getContextClassLoader()
加载类时应使用启动的应用程序(默认情况下,大多数库和框架都使用)。尝试使用加载嵌套的jar类ClassLoader.getSystemClassLoader()
失败。java.util.Logging
始终使用系统类加载器。因此,您应该考虑使用其他日志记录实现。
6.替代单罐解决方案
如果上述限制意味着您不能使用Spring Boot Loader,请考虑以下替代方法:
- JarClassLoader
- 一罐
- Gradle Shadow插件