可执行 Jar
1. 嵌套JARs
Java 没有提供任何标准方式来加载嵌套的 jar 文件(即本身包含在 jar 中的 jar 文件)。 如果你需要分发一个可以从命令行运行而无需解压的自包含应用,这可能会带来问题。
为了解决这个问题,许多开发者使用“着色”罐子。 阴影罐子将所有类别,所有罐子的集合,打包到一个“超罐子”中。 阴影jar的问题在于很难看清实际应用里有哪些库。 如果同一个文件名(但内容不同)在多个jar中使用,也会带来问题。 Spring Boot 采取了不同的方法,允许你直接嵌套罐子。
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
应用类应置入嵌套启动-INF/类目录。
依赖应放在嵌套中启动-INF/LIB目录。
1.2. 可执行战争文件结构
兼容 Spring Boot Loader 的战争文件应按以下结构排列:
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-提供的.
1.3. 索引文件
兼容 Spring Boot Loader 的 jar 和 war 归档可以在启动步兵/目录。
一个classpath.idx文件可以同时用于 jar 和 wars,并提供了将 jar 添加到类路径的顺序。
这layers.idx文件只能用于 jar,并且允许将 jar 拆分为逻辑层,用于 Docker 或 OCI 图像创建。
索引文件遵循兼容 YAML 的语法,便于被第三方工具轻松解析。 然而,这些文件内部并未解析为YAML格式,必须按照下文描述的格式编写才能使用。
1.4. 类路径索引
类路径索引文件可以提供在BOOT-INF/classpath.idx.
通常,它由 Spring Boot 的 Maven 和 Gradle 构建插件自动生成。
它提供了 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 index 文件Java -jar.
在从 IDE 运行应用或使用 Maven 时,不会使用Spring Boot:跑或者Gradle的启动运行. |
| 启用可重现构建时,类路径索引文件中的条目按字母顺序排序。 |
1.5. 层指数
图层索引文件可以提供于BOOT-INF/layers.idx.
它列出了层数以及罐子中应包含的部分。
图层的编写顺序是按照添加到 Docker/OCI 镜像的顺序。
图层名称以引号字符串形式表示,前置破折号()并加冒号("-·"":")后缀。
层内容可以是文件名或目录名,以引号字符串写成,前缀为空格、空间、破折号、空格()。
目录名以 结尾,文件名则不以 结尾。
当使用目录名称时,意味着该目录内的所有文件都在同一层。"··-·"/
图层索引的典型例子是:
- "dependencies": - "BOOT-INF/lib/dependency1.jar" - "BOOT-INF/lib/dependency2.jar" - "application": - "BOOT-INF/classes/" - "META-INF/"
2. Spring Boot 的“NestedJarFile” 类
用于支持加载嵌套jar的核心类为org.springframework.boot.loader.jar.NestedJarFile.
它允许你从嵌套的子jar数据加载jar内容。
首次加载时,每个人的位置JarEntry映射到外罐的物理文件偏移量,如下示例所示:
myapp.jar +-------------------+-------------------------+ | /BOOT-INF/classes | /BOOT-INF/lib/mylib.jar | |+-----------------+||+-----------+----------+| || A.class ||| B.class | C.class || |+-----------------+||+-----------+----------+| +-------------------+-------------------------+ ^ ^ ^ 0063 3452 3980
前面的例子展示了A级可以在/BOOT-INF/类在myapp.jar位置0063.B级嵌套罐子实际上可以在myapp.jar位置3452和C级位于位置3980.
掌握这些信息后,我们可以通过寻找外部罐子的相应部分来加载特定的嵌套条目。 我们不需要解压档案,也不需要将所有录入数据读入内存。
3. 启动可执行罐
这org.springframework.boot.loader.launch.Launcher类是一个特殊的引导类,用作可执行 jar 的主要入口。
而是实际情况主级在你的jar文件中,它被用来设置合适的ClassLoader最终,你的main()方法。
发射器分为三个子类别(JarLauncher,战争发射器和PropertiesLauncher).
它们的目的是加载资源(。类文件等)来自嵌套的jar文件或目录中的war文件(而非显式的类路径文件)。
在JarLauncher和战争发射器,嵌套路径是固定的。JarLauncher看着启动-INF/lib/和战争发射器看着WEB-INF/lib/和WEB-INF/lib-provided/.
如果你想要更多,可以在那些地方加额外的罐子。
这PropertiesLauncher看着启动-INF/lib/默认存储在你的应用档案中。
你可以通过设置一个名为LOADER_PATH或loader.path在loader.properties(这是目录、档案或档案内目录的逗号分隔列表)。
3.1. 发射器清单
你需要指定一个合适的发射作为主级属性元步兵/显化。双重.
你真正想启动的类(即包含主要方法)应在起始级属性。
以下示例展示了一个典型的清单。双重对于可执行的jar文件:
Main-Class: org.springframework.boot.loader.launch.JarLauncher Start-Class: com.mycompany.project.MyApplication
对于战争档案,情况如下:
Main-Class: org.springframework.boot.loader.launch.WarLauncher Start-Class: com.mycompany.project.MyApplication
你无需具体说明类路径你清单文件中的条目。
类路径是从嵌套的jar推导出来的。 |
4. PropertiesLauncher 功能
PropertiesLauncher有一些特殊功能可以通过外部属性(系统属性、环境变量、manifest 条目或)来启用loader.properties).
下表描述了这些性质:
| 钥匙 | 目的 |
|---|---|
|
逗号分隔的类路径,例如 |
|
用于解析 中的相对路径 |
|
主要方法的默认参数(空格分离)。 |
|
要启动的主类名称(例如, |
|
属性文件名称(例如, |
|
路径到属性文件(例如, |
|
布尔标志表示所有属性都应添加到系统属性中。
它默认为 |
当被指定为环境变量或清单条目时,应使用以下名称:
| 钥匙 | 清单登记 | 环境变量 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
构建插件会自动移动主级归属为起始级当超级罐子建成时。
如果你用这个,可以通过主级属性与省略起始级. |
以下规则适用于与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:前缀。 -
loader.path(若为空) 默认为启动-INF/LIB(指本地目录,若运行于归档则是嵌套目录)。 因此,PropertiesLauncher表现为JarLauncher当没有提供额外的配置时。 -
loader.path不能用于配置 的位置loader.properties(用于搜索后者的类路径是 JVM 类路径,当PropertiesLauncher启动了)。 -
占位符替换是通过系统变量和环境变量,以及属性文件本身在所有值上进行的。
-
属性的搜索顺序(在需要在多个地方查找时)是环境变量、系统属性,
loader.properties爆炸的档案清单,以及档案清单。
5. 可执行的瓶子限制
在使用Spring Boot Loader打包的应用程序时,你需要考虑以下限制:
-
拉链式压缩: 这
拉链门对于嵌套的jar,必须通过使用ZipEntry.已存储方法。 这是必要的,以便我们能够直接在嵌套罐中寻找单个内容。 嵌套jar文件本身的内容仍然可以压缩,外jar中的任何其他条目也可以。
-
系统类加载器: 启动应用应使用
Thread.getContextClassLoader()加载类时(大多数库和框架默认都是这样)。 尝试加载嵌套的jar类ClassLoader.getSystemClassLoader()失败。java.util.logging始终使用系统的 classloader。 因此,你应该考虑不同的日志实现方式。