Spring Boot 支持可执行的 jar 格式
这些模块允许 Spring Boot 支持可执行的 jar 和 war 文件。 如果您使用 Maven 插件或 Gradle 插件,则会自动生成可执行 jar,您通常不需要知道它们如何工作的详细信息。spring-boot-loader
如果您需要从不同的构建系统创建可执行 jar,或者您只是对底层技术感到好奇,本附录提供了一些背景知识。
1. 嵌套罐
Java 不提供任何标准方法来加载嵌套的 jar 文件(即本身包含在 jar 中的 jar 文件)。 如果您需要分发无需解压缩即可从命令行运行的独立应用程序,则可能会出现问题。
为了解决这个问题,许多开发人员使用“阴影”罐子。 一个阴影罐子将所有类别,从所有罐子,打包到一个“超级罐子”中。 阴影罐的问题在于很难看到应用程序中实际存在哪些库。 如果在多个 jar 中使用相同的文件名(但内容不同),也可能出现问题。 Spring Boot 采用了不同的方法,让你直接嵌套罐子。
1.1. 可执行 jar 文件结构
Spring 引导加载程序兼容的 jar 文件应按以下方式构建:
应用程序类应放在嵌套目录中。 依赖项应放置在嵌套目录中。BOOT-INF/classes
BOOT-INF/lib
1.2. 可执行战争文件结构
Spring 引导加载程序兼容的战争文件应按以下方式构建:
依赖项应放置在嵌套目录中。 应放置运行嵌入式时需要但在部署到传统 Web 容器时不需要的任何依赖项。WEB-INF/lib
WEB-INF/lib-provided
1.3. 索引文件
Spring 引导加载程序兼容的 jar 和 war 存档可以在目录下包含额外的索引文件。 可以为 jar 和 wars 提供 Afile,它提供了应将 jar 添加到类路径中的顺序。 该文件只能用于 jar,它允许将 jar 拆分为逻辑层以进行 Docker/OCI 映像创建。BOOT-INF/
classpath.idx
layers.idx
索引文件遵循 YAML 兼容语法,以便第三方工具可以轻松解析它们。 但是,这些文件不会在内部解析为 YAML,它们必须完全按照下面描述的格式编写才能使用。
1.4. 类路径索引
可以在 中提供类路径索引文件。 它按应添加到类路径的顺序提供 jar 名称(包括目录)的列表。 每行必须以短划线空格 () 开头,名称必须用双引号引起来。BOOT-INF/classpath.idx
"-·"
例如,给定以下 jar:
索引文件如下所示:
1.5. 图层索引
可以在 中提供图层索引文件。 它提供了图层列表以及应包含在其中的罐子部分。 层的写入顺序是按照它们应添加到 Docker/OCI 映像的顺序编写的。 图层名称以带引号的字符串形式编写,前缀为短划线空格 () 和冒号 () 后缀。 图层内容是文件或目录名称,以带引号的字符串形式写入,前缀为空格短划线空格 ()。 目录名称以结尾,文件名不以结尾。 使用目录名称时,表示该目录中的所有文件都位于同一图层中。BOOT-INF/layers.idx
"-·"
":"
"··-·"
/
图层索引的典型示例是:
2. Spring Boot的“JarFile”类
用于支持加载嵌套 jar 的核心类是。 它允许您从标准 jar 文件或嵌套的子 jar 数据加载 jar 内容。 首次加载时,每个位置映射到外部 jar 的物理文件偏移量,如以下示例所示:org.springframework.boot.loader.jar.JarFile
JarEntry
前面的示例显示了如何找到 ininat 位置。从嵌套的 jar 实际上可以找到 inat 位置,并且是 at position。A.class
/BOOT-INF/classes
myapp.jar
0063
B.class
myapp.jar
3452
C.class
3980
有了这些信息,我们可以通过寻找外 jar 的适当部分来加载特定的嵌套条目。 我们不需要解压缩存档,也不需要将所有条目数据读入内存。
2.1. 与标准Java“jarFile”的兼容性
Spring 引导加载程序努力保持与现有代码和库的兼容性。 该方法返回一个打开与Java兼容的连接并且可以与Java一起使用。org.springframework.boot.loader.jar.JarFile
java.util.jar.JarFile
getURL()
URL
java.net.JarURLConnection
URLClassLoader
3. 启动可执行罐
Theclass 是一个特殊的引导类,用作可执行 jar 的主入口点。 它是你的jar文件中的实际,它用于设置一个适当的并最终调用你的方法。org.springframework.boot.loader.Launcher
Main-Class
URLClassLoader
main()
有三个启动器子类(、和)。 它们的目的是从嵌套的 jar 文件或目录中的 war 文件(而不是类路径上的那些显式文件)加载资源(文件等)。 在 and 的情况下,嵌套路径是固定的。查找在,和 查找在和。 如果需要更多,可以在这些位置添加额外的罐子。 默认情况下,在您的应用程序存档中查找。 您可以通过设置 calledorin 的环境变量(这是目录、存档或存档中的目录的逗号分隔列表)来添加其他位置。JarLauncher
WarLauncher
PropertiesLauncher
.class
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. 启动器清单
您需要指定一个适当的属性。 要在属性中指定要启动的实际类(即包含 amethod的类)。Launcher
Main-Class
META-INF/MANIFEST.MF
main
Start-Class
以下示例显示了可执行文件的典型特征 jar 文件:MANIFEST.MF
对于战争文件,它将如下所示:
这些模块允许 Spring Boot 支持可执行的 jar 和 war 文件。 如果您使用 Maven 插件或 Gradle 插件,则会自动生成可执行 jar,您通常不需要知道它们如何工作的详细信息。spring-boot-loader
如果您需要从不同的构建系统创建可执行 jar,或者您只是对底层技术感到好奇,本附录提供了一些背景知识。
1. 嵌套罐
Java 不提供任何标准方法来加载嵌套的 jar 文件(即本身包含在 jar 中的 jar 文件)。 如果您需要分发无需解压缩即可从命令行运行的独立应用程序,则可能会出现问题。
为了解决这个问题,许多开发人员使用“阴影”罐子。 一个阴影罐子将所有类别,从所有罐子,打包到一个“超级罐子”中。 阴影罐的问题在于很难看到应用程序中实际存在哪些库。 如果在多个 jar 中使用相同的文件名(但内容不同),也可能出现问题。 Spring Boot 采用了不同的方法,让你直接嵌套罐子。
1.1. 可执行 jar 文件结构
Spring 引导加载程序兼容的 jar 文件应按以下方式构建:
应用程序类应放在嵌套目录中。 依赖项应放置在嵌套目录中。BOOT-INF/classes
BOOT-INF/lib
1.2. 可执行战争文件结构
Spring 引导加载程序兼容的战争文件应按以下方式构建:
依赖项应放置在嵌套目录中。 应放置运行嵌入式时需要但在部署到传统 Web 容器时不需要的任何依赖项。WEB-INF/lib
WEB-INF/lib-provided
1.3. 索引文件
Spring 引导加载程序兼容的 jar 和 war 存档可以在目录下包含额外的索引文件。 可以为 jar 和 wars 提供 Afile,它提供了应将 jar 添加到类路径中的顺序。 该文件只能用于 jar,它允许将 jar 拆分为逻辑层以进行 Docker/OCI 映像创建。BOOT-INF/
classpath.idx
layers.idx
索引文件遵循 YAML 兼容语法,以便第三方工具可以轻松解析它们。 但是,这些文件不会在内部解析为 YAML,它们必须完全按照下面描述的格式编写才能使用。
1.4. 类路径索引
可以在 中提供类路径索引文件。 它按应添加到类路径的顺序提供 jar 名称(包括目录)的列表。 每行必须以短划线空格 () 开头,名称必须用双引号引起来。BOOT-INF/classpath.idx
"-·"
例如,给定以下 jar:
索引文件如下所示:
1.5. 图层索引
可以在 中提供图层索引文件。 它提供了图层列表以及应包含在其中的罐子部分。 层的写入顺序是按照它们应添加到 Docker/OCI 映像的顺序编写的。 图层名称以带引号的字符串形式编写,前缀为短划线空格 () 和冒号 () 后缀。 图层内容是文件或目录名称,以带引号的字符串形式写入,前缀为空格短划线空格 ()。 目录名称以结尾,文件名不以结尾。 使用目录名称时,表示该目录中的所有文件都位于同一图层中。BOOT-INF/layers.idx
"-·"
":"
"··-·"
/
图层索引的典型示例是:
2. Spring Boot的“JarFile”类
用于支持加载嵌套 jar 的核心类是。 它允许您从标准 jar 文件或嵌套的子 jar 数据加载 jar 内容。 首次加载时,每个位置映射到外部 jar 的物理文件偏移量,如以下示例所示:org.springframework.boot.loader.jar.JarFile
JarEntry
前面的示例显示了如何找到 ininat 位置。从嵌套的 jar 实际上可以找到 inat 位置,并且是 at position。A.class
/BOOT-INF/classes
myapp.jar
0063
B.class
myapp.jar
3452
C.class
3980
有了这些信息,我们可以通过寻找外 jar 的适当部分来加载特定的嵌套条目。 我们不需要解压缩存档,也不需要将所有条目数据读入内存。
2.1. 与标准Java“jarFile”的兼容性
Spring 引导加载程序努力保持与现有代码和库的兼容性。 该方法返回一个打开与Java兼容的连接并且可以与Java一起使用。org.springframework.boot.loader.jar.JarFile
java.util.jar.JarFile
getURL()
URL
java.net.JarURLConnection
URLClassLoader
3. 启动可执行罐
Theclass 是一个特殊的引导类,用作可执行 jar 的主入口点。 它是你的jar文件中的实际,它用于设置一个适当的并最终调用你的方法。org.springframework.boot.loader.Launcher
Main-Class
URLClassLoader
main()
有三个启动器子类(、和)。 它们的目的是从嵌套的 jar 文件或目录中的 war 文件(而不是类路径上的那些显式文件)加载资源(文件等)。 在 and 的情况下,嵌套路径是固定的。查找在,和 查找在和。 如果需要更多,可以在这些位置添加额外的罐子。 默认情况下,在您的应用程序存档中查找。 您可以通过设置 calledorin 的环境变量(这是目录、存档或存档中的目录的逗号分隔列表)来添加其他位置。JarLauncher
WarLauncher
PropertiesLauncher
.class
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. 启动器清单
您需要指定一个适当的属性。 要在属性中指定要启动的实际类(即包含 amethod的类)。Launcher
Main-Class
META-INF/MANIFEST.MF
main
Start-Class
以下示例显示了可执行文件的典型特征 jar 文件:MANIFEST.MF
对于战争文件,它将如下所示:
以下规则适用于使用:PropertiesLauncher
-
loader.properties
在 in、 类路径的根目录中搜索,然后在 in 中搜索。 使用具有该名称的文件存在的第一个位置。loader.home
classpath:/BOOT-INF/classes
-
loader.home
是附加属性文件的目录位置(仅当未指定时覆盖默认值)。loader.config.location
-
loader.path
可以包含目录(以递归方式扫描 jar 和 zip 文件)、归档路径、归档文件中扫描 JAR 文件的目录(例如,)或通配符模式(对于缺省 JVM 行为)。 存档路径可以相对于文件系统中带有前缀的任意位置。dependencies.jar!/lib
loader.home
jar:file:
-
loader.path
(如果为空)默认为(表示本地目录或嵌套目录(如果从存档运行)。 因此,其行为与未提供其他配置时相同。BOOT-INF/lib
PropertiesLauncher
JarLauncher
-
loader.path
不能用于配置的位置(用于搜索后者的类路径是启动时的 JVM 类路径)。loader.properties
PropertiesLauncher
- 占位符替换是在使用之前从系统和环境变量以及所有值的属性文件本身完成的。
- 属性的搜索顺序(在多个位置查找是有意义的)是环境变量、系统属性、松散存档清单和存档清单。
loader.properties
5. 可执行 Jar 限制
在使用 Spring 引导加载程序打包的应用程序时,您需要考虑以下限制:
- 压缩压缩: 对于嵌套的罐子,必须使用该方法保存。 这是必需的,以便我们可以直接查找嵌套 jar 中的单个内容。 嵌套 jar 文件本身的内容仍然可以压缩,外部 jar 中的任何其他条目也可以压缩。
ZipEntry
ZipEntry.STORED
- 系统类加载器: 启动的应用程序应在加载类时使用(默认情况下,大多数库和框架都这样做)。 尝试装入嵌套的 jar 类失败。始终使用系统类装入器。 因此,应考虑使用其他日志记录实现。
Thread.getContextClassLoader()
ClassLoader.getSystemClassLoader()
java.util.Logging