可执行 Jar
1. 嵌套 JAR
Java 不提供任何标准方法来加载嵌套的 jar 文件(即,本身包含在 jar 中的 jar 文件)。 如果您需要分发一个无需解压缩即可从命令行运行的独立应用程序,这可能会出现问题。
为了解决这个问题,许多开发人员使用“阴影”jar。 阴影 jar 将所有 jar 中的所有类打包到一个 “uber jar” 中。 着色 jar 的问题在于,很难看到您的应用程序中实际存在哪些库。 如果在多个 jar 中使用相同的文件名(但内容不同),也可能出现问题。 Spring Boot 采用不同的方法,让您实际上直接嵌套 jar。
1.1. 可执行 jar 文件结构
与 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
1.2. 可执行的 war 文件结构
与 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 容器时不需要的任何依赖项都应放在 .WEB-INF/lib
WEB-INF/lib-provided
1.3. 索引文件
与 Spring Boot Loader 兼容的 jar 和 war 存档可以在目录下包含其他索引文件。
可以为 jar 和 war 提供一个文件,它提供了应将 jar 添加到 Classpath 的顺序。
该文件只能用于 jar,并且允许将 jar 拆分为逻辑层以创建 Docker/OCI 映像。BOOT-INF/
classpath.idx
layers.idx
索引文件遵循 YAML 兼容语法,因此第三方工具可以轻松解析它们。 但是,这些文件在内部不会解析为 YAML,它们必须以下面描述的格式编写才能使用。
1.4. 类路径索引
类路径索引文件可以在 中提供。
通常,它是由 Spring Boot 的 Maven 和 Gradle 构建插件自动生成的。
它提供了一个 jar 名称(包括目录)的列表,其顺序是它们应该添加到 Classpath 中的顺序。
当由 build 插件生成时,此 classpath 排序与 build system 用于运行和测试应用程序的 classpath 排序匹配。
每行必须以破折号 () 开头,名称必须用双引号括起来。BOOT-INF/classpath.idx
"-·"
例如,给定以下 jar:
example.jar | +-META-INF | +-... +-BOOT-INF +-classes | +... +-lib +-dependency1.jar +-dependency2.jar
索引文件将如下所示:
- "BOOT-INF/lib/dependency2.jar" - "BOOT-INF/lib/dependency1.jar"
Spring Boot 仅在使用 jar 或 war 文件执行时使用 classpath 索引文件。
从 IDE 运行应用程序或使用 Maven 或 Gradle 的 .java -jar spring-boot:run bootRun |
启用可重现构建时,类路径索引文件中的条目将按字母顺序排序。 |
1.5. 图层索引
层索引文件可以在 中提供。
它提供了一个层列表以及应包含在其中的 jar 部分。
层按照应添加到 Docker/OCI 映像的顺序写入。
图层名称写为带引号的字符串,前缀为破折号 () 和冒号 () 后缀。
图层内容是文件或目录名称,以带引号的字符串编写,前缀为 space、space、dash space、() 。
目录名称以 结尾,文件名则不以 . 结尾。
使用目录名称时,表示该目录内的所有文件都位于同一层中。BOOT-INF/layers.idx
"-·"
":"
"··-·"
/
层索引的一个典型示例是:
- "dependencies": - "BOOT-INF/lib/dependency1.jar" - "BOOT-INF/lib/dependency2.jar" - "application": - "BOOT-INF/classes/" - "META-INF/"
2. Spring Boot 的 “NestedJarFile” 类
用于支持加载嵌套 jar 的核心类是 。
它允许您从嵌套的子 jar 数据加载 jar 内容。
首次加载时,每个 jar 的位置都映射到外部 jar 的物理文件偏移量,如以下示例所示:org.springframework.boot.loader.jar.NestedJarFile
JarEntry
myapp.jar +-------------------+-------------------------+ | /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar | |+-----------------+||+-----------+----------+| || A.class ||| B.class | C.class || |+-----------------+||+-----------+----------+| +-------------------+-------------------------+ ^ ^ ^ 0063 3452 3980
前面的示例显示了如何在 at 位置 中找到。 从嵌套的 jar 中实际上可以在 at position 中找到,并且位于 at position 。A.class
/BOOT-INF/classes
myapp.jar
0063
B.class
myapp.jar
3452
C.class
3980
有了这些信息,我们可以通过查找外部 jar 的适当部分来加载特定的嵌套条目。 我们不需要解压缩存档,也不需要将所有 entry 数据读入内存。
3. 启动可执行 Jar
该类是一个特殊的引导类,用作可执行 jar 的主入口点。
它是 jar 文件中的实际文件,用于设置适当的方法并最终调用方法。org.springframework.boot.loader.launch.Launcher
Main-Class
ClassLoader
main()
有三个Starters子类 (, , 和 )。
它们的目的是从目录中的嵌套 jar 文件或 war 文件(而不是 Classpath 上显式的那些文件)加载资源(文件等)。
在 和 的情况下,嵌套路径是固定的。 在 中查找 ,并在 中查找 和 。
如果需要更多,可以在这些位置添加额外的 jar。JarLauncher
WarLauncher
PropertiesLauncher
.class
JarLauncher
WarLauncher
JarLauncher
BOOT-INF/lib/
WarLauncher
WEB-INF/lib/
WEB-INF/lib-provided/
默认情况下,在应用程序存档中查找。
您可以通过设置名为 或 in 的环境变量(该变量是目录、存档或存档中的目录的逗号分隔列表)来添加其他位置。PropertiesLauncher
BOOT-INF/lib/
LOADER_PATH
loader.path
loader.properties
3.1. Starters清单
您需要指定一个 appropriate 作为 的属性。
应在属性中指定要启动的实际类(即包含方法的类)。Launcher
Main-Class
META-INF/MANIFEST.MF
main
Start-Class
以下示例显示了可执行 jar 文件的典型示例:MANIFEST.MF
Main-Class: org.springframework.boot.loader.launch.JarLauncher Start-Class: com.mycompany.project.MyApplication
对于 war 文件,它如下所示:
Main-Class: org.springframework.boot.loader.launch.WarLauncher Start-Class: com.mycompany.project.MyApplication
您无需在清单文件中指定条目。
类路径是从嵌套的 jar 中推导出来的。Class-Path |
4. PropertiesLauncher 功能
PropertiesLauncher
具有一些可通过外部属性(系统属性、环境变量、清单条目或 )启用的特殊功能。
下表描述了这些属性:loader.properties
钥匙 | 目的 |
---|---|
|
逗号分隔的类路径,例如 .
较早的条目优先,就像命令行中的常规条目一样。 |
|
用于解析 中的相对路径。
例如,given ,则是 Classpath 位置(以及该目录中的所有 jar 文件)。
此属性还用于查找文件,如以下示例所示,它默认为 . |
|
main 方法的默认参数(以空格分隔)。 |
|
要启动的主类的名称(例如,)。 |
|
属性文件的名称(例如 )。
它默认为 . |
|
属性文件的路径(例如 )。
它默认为 . |
|
Boolean 标志,指示应将所有属性添加到系统属性中。
它默认为 . |
当指定为环境变量或清单条目时,应使用以下名称:
钥匙 | 清单条目 | 环境变量 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
构建插件会自动将属性移动到构建 uber jar 时。
如果使用该选项,请使用 attribute 并省略 来指定要启动的类的名称。Main-Class Start-Class Main-Class Start-Class |
以下规则适用于使用 :PropertiesLauncher
-
loader.properties
在 中搜索,然后在 Classpath 的根目录中搜索,然后在 中搜索。 使用具有该名称的文件所在的第一个位置。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
不能用于配置的位置(用于搜索后者的 Classpath 是启动时的 JVM Classpath)。loader.properties
PropertiesLauncher
-
占位符替换是在使用之前根据 System 和 environment variables 以及 properties 文件本身对所有值完成的。
-
属性的搜索顺序(在多个位置查找是有意义的)是环境变量、系统属性、松散的存档清单和存档清单。
loader.properties
5. 可执行 Jar 限制
在使用 Spring Boot Loader 打包的应用程序时,需要考虑以下限制:
-
Zip entry 压缩: 必须使用该方法保存嵌套 jar 的 for a nested jar。 这是必需的,以便我们可以直接查找嵌套 jar 中的单个内容。 嵌套 jar 文件本身的内容仍然可以压缩,外部 jar 中的任何其他条目也可以压缩。
ZipEntry
ZipEntry.STORED
-
系统 classLoader 中: 启动的应用程序应在加载类时使用(默认情况下,大多数库和框架都这样做)。 尝试加载嵌套的 jar 类失败。 始终使用 System 类加载器。 因此,您应该考虑不同的日志记录实现。
Thread.getContextClassLoader()
ClassLoader.getSystemClassLoader()
java.util.Logging