可执行 Jar

1. 嵌套 JAR

Java 不提供任何标准方法来加载嵌套的 jar 文件(即,本身包含在 jar 中的 jar 文件)。 如果您需要分发一个无需解压缩即可从命令行运行的独立应用程序,这可能会出现问题。spring-doc.cn

为了解决这个问题,许多开发人员使用“阴影”jar。 阴影 jar 将所有 jar 中的所有类打包到一个 “uber jar” 中。 着色 jar 的问题在于,很难看到您的应用程序中实际存在哪些库。 如果在多个 jar 中使用相同的文件名(但内容不同),也可能出现问题。 Spring Boot 采用不同的方法,让您实际上直接嵌套 jar。spring-doc.cn

1.1. 可执行 jar 文件结构

与 Spring Boot Loader 兼容的 jar 文件应按以下方式构建:spring-doc.cn

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/classesBOOT-INF/libspring-doc.cn

1.2. 可执行的 war 文件结构

与 Spring Boot Loader 兼容的 war 文件应按以下方式构建:spring-doc.cn

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/libWEB-INF/lib-providedspring-doc.cn

1.3. 索引文件

与 Spring Boot Loader 兼容的 jar 和 war 存档可以在目录下包含其他索引文件。 可以为 jar 和 war 提供一个文件,它提供了应将 jar 添加到 Classpath 的顺序。 该文件只能用于 jar,并且允许将 jar 拆分为逻辑层以创建 Docker/OCI 映像。BOOT-INF/classpath.idxlayers.idxspring-doc.cn

索引文件遵循 YAML 兼容语法,因此第三方工具可以轻松解析它们。 但是,这些文件在内部不会解析为 YAML,它们必须以下面描述的格式编写才能使用。spring-doc.cn

1.4. 类路径索引

类路径索引文件可以在 中提供。 通常,它是由 Spring Boot 的 Maven 和 Gradle 构建插件自动生成的。 它提供了一个 jar 名称(包括目录)的列表,其顺序是它们应该添加到 Classpath 中的顺序。 当由 build 插件生成时,此 classpath 排序与 build system 用于运行和测试应用程序的 classpath 排序匹配。 每行必须以破折号 () 开头,名称必须用双引号括起来。BOOT-INF/classpath.idx"-·"spring-doc.cn

例如,给定以下 jar:spring-doc.cn

example.jar
 |
 +-META-INF
 |  +-...
 +-BOOT-INF
    +-classes
    |  +...
    +-lib
       +-dependency1.jar
       +-dependency2.jar

索引文件将如下所示:spring-doc.cn

- "BOOT-INF/lib/dependency2.jar"
- "BOOT-INF/lib/dependency1.jar"
Spring Boot 仅在使用 jar 或 war 文件执行时使用 classpath 索引文件。 从 IDE 运行应用程序或使用 Maven 或 Gradle 的 .java -jarspring-boot:runbootRun
启用可重现构建时,类路径索引文件中的条目将按字母顺序排序。

1.5. 图层索引

层索引文件可以在 中提供。 它提供了一个层列表以及应包含在其中的 jar 部分。 层按照应添加到 Docker/OCI 映像的顺序写入。 图层名称写为带引号的字符串,前缀为破折号 () 和冒号 () 后缀。 图层内容是文件或目录名称,以带引号的字符串编写,前缀为 space、space、dash space、() 。 目录名称以 结尾,文件名则不以 . 结尾。 使用目录名称时,表示该目录内的所有文件都位于同一层中。BOOT-INF/layers.idx"-·"":""··-·"/spring-doc.cn

层索引的一个典型示例是:spring-doc.cn

- "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.NestedJarFileJarEntryspring-doc.cn

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/classesmyapp.jar0063B.classmyapp.jar3452C.class3980spring-doc.cn

有了这些信息,我们可以通过查找外部 jar 的适当部分来加载特定的嵌套条目。 我们不需要解压缩存档,也不需要将所有 entry 数据读入内存。spring-doc.cn

2.1. 与标准 Java “JarFile” 的兼容性

Spring Boot Loader 努力保持与现有代码和库的兼容性。 扩展自 和 应该作为直接替代品。org.springframework.boot.loader.jar.NestedJarFilejava.util.jar.JarFilespring-doc.cn

支持表单的嵌套 JAR URL,并打开与 兼容的连接。 这些可以与 Java 的 .jar:nested:/path/myjar.jar/!BOOT-INF/lib/mylib.jar!/B.classjava.net.JarURLConnectionURLClassLoaderspring-doc.cn

3. 启动可执行 Jar

该类是一个特殊的引导类,用作可执行 jar 的主入口点。 它是 jar 文件中的实际文件,用于设置适当的方法并最终调用方法。org.springframework.boot.loader.launch.LauncherMain-ClassClassLoadermain()spring-doc.cn

有三个Starters子类 (, , 和 )。 它们的目的是从目录中的嵌套 jar 文件或 war 文件(而不是 Classpath 上显式的那些文件)加载资源(文件等)。 在 和 的情况下,嵌套路径是固定的。 在 中查找 ,并在 中查找 和 。 如果需要更多,可以在这些位置添加额外的 jar。JarLauncherWarLauncherPropertiesLauncher.classJarLauncherWarLauncherJarLauncherBOOT-INF/lib/WarLauncherWEB-INF/lib/WEB-INF/lib-provided/spring-doc.cn

默认情况下,在应用程序存档中查找。 您可以通过设置名为 或 in 的环境变量(该变量是目录、存档或存档中的目录的逗号分隔列表)来添加其他位置。PropertiesLauncherBOOT-INF/lib/LOADER_PATHloader.pathloader.propertiesspring-doc.cn

3.1. Starters清单

您需要指定一个 appropriate 作为 的属性。 应在属性中指定要启动的实际类(即包含方法的类)。LauncherMain-ClassMETA-INF/MANIFEST.MFmainStart-Classspring-doc.cn

以下示例显示了可执行 jar 文件的典型示例:MANIFEST.MFspring-doc.cn

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

对于 war 文件,它如下所示:spring-doc.cn

Main-Class: org.springframework.boot.loader.launch.WarLauncher
Start-Class: com.mycompany.project.MyApplication
您无需在清单文件中指定条目。 类路径是从嵌套的 jar 中推导出来的。Class-Path

4. PropertiesLauncher 功能

PropertiesLauncher具有一些可通过外部属性(系统属性、环境变量、清单条目或 )启用的特殊功能。 下表描述了这些属性:loader.propertiesspring-doc.cn

钥匙 目的

loader.pathspring-doc.cn

逗号分隔的类路径,例如 . 较早的条目优先,就像命令行中的常规条目一样。lib,${HOME}/app/lib-classpathjavacspring-doc.cn

loader.homespring-doc.cn

用于解析 中的相对路径。 例如,given ,则是 Classpath 位置(以及该目录中的所有 jar 文件)。 此属性还用于查找文件,如以下示例所示,它默认为 .loader.pathloader.path=lib${loader.home}/libloader.properties/opt/app${user.dir}spring-doc.cn

loader.argsspring-doc.cn

main 方法的默认参数(以空格分隔)。spring-doc.cn

loader.mainspring-doc.cn

要启动的主类的名称(例如,)。com.app.Applicationspring-doc.cn

loader.config.namespring-doc.cn

属性文件的名称(例如 )。 它默认为 .launcherloaderspring-doc.cn

loader.config.locationspring-doc.cn

属性文件的路径(例如 )。 它默认为 .classpath:loader.propertiesloader.propertiesspring-doc.cn

loader.systemspring-doc.cn

Boolean 标志,指示应将所有属性添加到系统属性中。 它默认为 .falsespring-doc.cn

当指定为环境变量或清单条目时,应使用以下名称:spring-doc.cn

钥匙 清单条目 环境变量

loader.pathspring-doc.cn

Loader-Pathspring-doc.cn

LOADER_PATHspring-doc.cn

loader.homespring-doc.cn

Loader-Homespring-doc.cn

LOADER_HOMEspring-doc.cn

loader.argsspring-doc.cn

Loader-Argsspring-doc.cn

LOADER_ARGSspring-doc.cn

loader.mainspring-doc.cn

Start-Classspring-doc.cn

LOADER_MAINspring-doc.cn

loader.config.locationspring-doc.cn

Loader-Config-Locationspring-doc.cn

LOADER_CONFIG_LOCATIONspring-doc.cn

loader.systemspring-doc.cn

Loader-Systemspring-doc.cn

LOADER_SYSTEMspring-doc.cn

构建插件会自动将属性移动到构建 uber jar 时。 如果使用该选项,请使用 attribute 并省略 来指定要启动的类的名称。Main-ClassStart-ClassMain-ClassStart-Class

以下规则适用于使用 :PropertiesLauncherspring-doc.cn

  • loader.properties在 中搜索,然后在 Classpath 的根目录中搜索,然后在 中搜索。 使用具有该名称的文件所在的第一个位置。loader.homeclasspath:/BOOT-INF/classesspring-doc.cn

  • loader.home是附加属性文件的目录位置(仅在未指定时覆盖默认值)。loader.config.locationspring-doc.cn

  • loader.path可以包含目录(以递归方式扫描 jar 和 zip 文件)、存档路径、存档中扫描 jar 文件的目录(例如)或通配符模式(用于默认 JVM 行为)。 存档路径可以是相对于文件系统的路径,也可以是文件系统中带有前缀的任意位置。dependencies.jar!/libloader.homejar:file:spring-doc.cn

  • loader.path(如果为空)默认为 (表示本地目录,如果从存档运行,则为嵌套目录)。 因此,其行为与未提供其他配置时的行为相同。BOOT-INF/libPropertiesLauncherJarLauncherspring-doc.cn

  • loader.path不能用于配置的位置(用于搜索后者的 Classpath 是启动时的 JVM Classpath)。loader.propertiesPropertiesLauncherspring-doc.cn

  • 占位符替换是在使用之前根据 System 和 environment variables 以及 properties 文件本身对所有值完成的。spring-doc.cn

  • 属性的搜索顺序(在多个位置查找是有意义的)是环境变量、系统属性、松散的存档清单和存档清单。loader.propertiesspring-doc.cn

5. 可执行 Jar 限制

在使用 Spring Boot Loader 打包的应用程序时,需要考虑以下限制:spring-doc.cn

  • Zip entry 压缩: 必须使用该方法保存嵌套 jar 的 for a nested jar。 这是必需的,以便我们可以直接查找嵌套 jar 中的单个内容。 嵌套 jar 文件本身的内容仍然可以压缩,外部 jar 中的任何其他条目也可以压缩。ZipEntryZipEntry.STOREDspring-doc.cn

  • 系统 classLoader 中: 启动的应用程序应在加载类时使用(默认情况下,大多数库和框架都这样做)。 尝试加载嵌套的 jar 类失败。 始终使用 System 类加载器。 因此,您应该考虑不同的日志记录实现。Thread.getContextClassLoader()ClassLoader.getSystemClassLoader()java.util.Loggingspring-doc.cn

6. 替代单罐解决方案

如果上述限制意味着您不能使用 Spring Boot Loader,请考虑以下替代方案:spring-doc.cn