JAVA 可执行文件格式

JAVA 可执行文件格式

springboot 程序使用 Maven PLugin插件编译时,可以生成可执行的 jar 和 war 程序。其核心原理是 spring-boot-loader 模块,详细原理如下

1 嵌套 JARS

java 本身不支持任何标准的加载嵌套 jar 的方式,要解决该问题,很多人使用 sharded jars 方式去打包程序,将所有 jar 包从新打包为一个独立的 “union-all.jar” 。但是 shared jars 方法使得很难判断应用程序中代码的归属、同时可能存在部分文件名冲突问题。

springboot 使用一种不同的方式实现嵌套 jar。

1.1 可执行 Jar 文件结构

springboot 加载 jar 文件结构如下:

pmsuite-web-5.4.1-SNAPSHOT.jar
 |
 +-META-INF
 |  +-MANIFEST.MF
 +-org
 |  +-springframework
 |     +-boot
 |        +-loader
 |           +-<spring boot loader classes> # springboot 提供加载机制实现
 +-BOOT-INF
    +-classes
    |  +-cn
    |     +-pinming
    |        +-suite
    |            +-SuiteApplication.class
    |            +- ...
    |  +-static
    |  +-templates
    |  +-application.yml
    |  +-spring-config.xml
    |  +-....
    +-lib
       +-druid-1.1.23.jar
       +-dubbo-2.7.15.jar
       +-...

MANIFEST.MF 文件内容

Manifest-Version: 1.0
Implementation-Title: pmsuite-web
Implementation-Version: 5.4.1-SNAPSHOT
Built-By: Administrator
Specification-Title: pmsuite-web
Implementation-Vendor-Id: cn.pinming
Spring-Boot-Version: 2.1.3.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: cn.pinming.pmsuite.SuiteApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.8.1
Build-Jdk: 1.8.0_131
Specification-Version: 5.4
Implementation-URL: https://projects.spring.io/spring-boot/#/spring-bo
 ot-starter-parent/pmsuite-boot-project/pmsuite/pmsuite-basic-parent/p
 msuite-web

按文件结构约定依赖jar包必须放在 WEB-INF/lib 下,任何运行时必须但部署到传统web容器时不必须的依赖放到 WEB-INF/lib-provided 目录下,而应用程序的 classes 必须放在 BOOT-INF/classes 目录下。

1.2 索引文件

Spring Boot Loader-compatible jar and war 文件可以 在 BOOT-INF/ 目录下存放扩展的索引文件。 一个 classpath.idx 文件可以为 jar 和 war 文件提供扩展 jars 依赖,而 layers.idx 仅仅为 jar 可执行文件服务。

索引文件使用 YAML 兼容语法。索引文件案例:

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

索引文件如下:

- "BOOT-INF/lib/dependency2.jar"
- "BOOT-INF/lib/dependency1.jar"

2. Spring Boot 加载 jar file 机制

springboot 加载 嵌套jars 核心入口 org.springframework.boot.loader.jar.JarFile 。该程序从一个标准 jar 文件 或 嵌套子 jar 文件中加载数据。

3. 执行jar

springboot 使用 org.springframework.boot.loader.Launcher 作为 java 程序加载主程序。该程序是一个 springboot 启动程序。

该启动程序包括三个子加载程序 JarLauncher, WarLauncher, and PropertiesLauncher。

4 PropertiesLauncher

PropertiesLauncher 加载一些扩展特性(比如系统配置、环境变量、mainfest 入口、或加载配置)。详细配置清单如下:

键值用途
loader.path使用逗号分割classpath,如 ${home}/app/lib。 类似 javac命令行的 -classpath 参数
loader.homeloader.path 或 loader.propertis 中如果使用相对目录时的跟目录。
loader.args程序启动参数,多个参数使用空格分割
loader.main程序启动的 main-class,如 SuiteApplication.class
loader.config.nameloader配置名称
loader.config.locationloader配置路径,默认 classpath:loader.propertis
loader.system判断配置是否加载到系统配置中,默认 false
  • PropertiesLauncher工作规则:

loader.properties: 先从loader.home,如果找不到查询classpath跟目录,最后查询 classpath:/BOOT-INF/classes。 使用最先找到的配置。
loader.home:只有在loader.config.location为配置时,才会从该目录加载扩展配置(覆盖默认配置)。
loader.path:可以包含目录(包含 jar 或 zip文件)、JAR归档文件路径(内容包括诸如:dependencies.jar!/lib)、正则表达式。
loader.path:默认值为 BOOT-INF/lib (表示从嵌套 jar归档文件中加载),该情况下不需要加载额外配置信息。
配置信息搜索顺序:environment variables, system properties, loader.properties, the exploded archive manifest, and the archive manifest.

案例

使用 loader.path 方式启动 springboot程序

  • Maven plugin 配置

       <plugin>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-maven-plugin</artifactId>
           <configuration>
               <layout>ZIP</layout>
               <includes>
                   <include>
                       <groupId>non-exists</groupId>
                       <artifactId>non-exists</artifactId>
                   </include>
               </includes>
           </configuration>
           <executions>
               <execution>
                   <goals>
                      <goal>repackage</goal>
                   </goals>
               </execution>
           </executions>
      </plugin>
       <!--拷贝依赖到jar外面的lib目录-->
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-dependency-plugin</artifactId>
          <executions>
              <execution>
                  <id>copy</id>
                  <phase>package</phase>
                  <goals>
                      <goal>copy-dependencies</goal>
                  </goals>
                  <configuration>
                      <!--指定的依赖路径-->
                      <outputDirectory>
                          ${project.build.directory}/lib
                      </outputDirectory>
                  </configuration>
              </execution>
          </executions>
      </plugin>
    1. 配置 layout 修改为 ZIP,使得启动的时候能够设别 loader.path属性
    2. 配置 include 为 non-exists,lib包 只包含 non-exists 包,而non-exists不存在,使用不打包lib依赖,这样就能保障所有依赖统一走 loader.path
    3. 使用 maven-dependency-plugin 独立打包依赖
  • 生成目录结构如下:

      +-target
       |  +- pm-bigdata-web.jar
       |  +- lib\
       |     +- ...
  • 启动脚本

      java -jar -Dloader.path=lib -Dspring.config.location=./config/application.yml pm-bigdata-web.jar

java 外部lib

java -jar -Djava.ext.dirs=./libs

如果在libs内 ,命令-Djava.ext.dirs=参数为./ ,如果生成jar与libs同级那么改为./libs 意思就是告诉jar 我的依赖jar包相对于我要执行的jar包的位置在哪里

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值