文章目录

  • 前言
  • 一、JAR是什么?
  • 二、嵌套JAR
    • 1.java官方不支持嵌套jar读取和加载
    • 2.嵌套“shade” jar 方案
    • 3.SpringBoot的解决方案
  • 三、SpringBoot的Executable Jars
    • 1.核心支持模块(spring-boot-loader)
    • 2.运行调试工具(JDWP)
      • 2.1.保姆级IDEA添加JDWP远程调试示例
    • 3.运行调试(java -jar)
      • 3.1.JAR启动入口:org.springframework.boot.loader.JarLauncher.main(String[] args)
      • 3.2.主启动方法:Launcher.launch(String[] args)
      • 3.3.应用自身启动实际执行的方法:MainMethodRunner.run()
  • 四、总结
    • 1.SpringBoot应用程序jar包可以通过java -jar 直接运行的原因?
    • 2.SpringBoot应用程序通过java -jar运行和直接在IDEA里面运行在类加载上最大的区别?
    • 3.MainMethodRunner的run() 方法的“mainMethod.invoke(null, new Object[] { this.args });”代码行中调用反射方法对象传“null”为什么能够正确执行?

前言

Spring Boot Maven 插件在 Apache Maven 中提供 Spring Boot 支持。 它允许您打包可执行的 jar 或战争存档、运行 Spring Boot 应用程序、生成构建信息并在运行集成测试之前启动 Spring Boot 应用程序。该插件可以创建包含应用程序所有依赖项的可执行存档(jar 文件和 war 文件),然后可以使用 “java -jar”命令运行应用程序。本文的JAR规范参照的版本为JDK8,SpringBoot调试的版本为2.7.6,参照本文调试的时候注意版本之间的差异。


一、JAR是什么?

JAR(Java Archive)是一种独立于平台的文件格式,是一种基于流行的ZIP文件格式, 用于将多个文件聚合为一个文件。多个 Java 小程序及其 必要的组件(.class 文件、图像和声音)可以是 捆绑在 JAR 文件中,随后下载到浏览器中 单个HTTP事务,大大提高了下载速度。这 JAR 格式还支持压缩,从而减小文件大小, 进一步缩短下载时间。此外,小程序作者 可以对 JAR 文件中的各个条目进行数字签名以进行身份验证 他们的起源,它是完全可扩展的。
JAR 文件是 本质上是一个包含可选 META-INF 的 zip 文件 目录。JAR 文件可以通过命令行 jar 工具创建,也可以使用 Java 平台中的 java.util.jar API 创建。对名称没有限制 JAR 文件,它可以是特定平台上的任何合法文件名。在许多情况下,JAR 文件不仅仅是简单的 java 存档 类文件和/或资源。它们被用作构建块 用于应用程序和扩展。META-INF 目录,如果 exists,用于存储包和扩展配置数据, 包括安全性、版本控制、扩展和服务。

  • oracle官方关于JDK8的Java Archive (JAR) Files的介绍文档

  • oracle官方关于JDK8版本将程序打包到JAR文件的介绍文档


二、嵌套JAR

嵌套JAR就是将很多依赖的JAR包打成到一个大的JAR包中,即JAR包中包含JAR包,Apache Maven提供了maven-shade-plugin插件支持这种嵌套打包。

1.java官方不支持嵌套jar读取和加载

Java 不提供任何标准方法来加载嵌套的 jar 文件(即本身包含在 jar 中的 jar 文件)。 如果您需要分发一个独立的应用程序,而该应用程序可以从命令行运行而无需解压缩,这可能会有问题(ClassNotFoundException),主要有如下两个:

  • java官方没有提供嵌套JAR读取的API实现
  • java官方没有提供嵌套JAR的类加载实现

java官方关于使用RMI下载动态java代码到VM进程运行的描述如下:
java.rmi.server.codebase 指定的类加载位置URL可以是jar包,也可以是‘/’结尾的类路径,但不可以是嵌套式的uber-jar包中的jar

2.嵌套“shade” jar 方案

为了解决这个问题,许多开发人员使用“shaded”jar。 一个“shaded” jar 将所有 jar 中的所有类打包到一个“uber jar”中。 “shaded” jar 的问题在于,很难看到应用程序中实际存在哪些库。 如果在多个 jar 中使用相同的文件名(但内容不同),也可能有问题,Apache Maven提供了maven-shade-plugin插件支持“shade”jar的打包。

  • Apache Maven Shade Plugin参照文档

3.SpringBoot的解决方案

Spring Boot 采用了一种不同的方法,可以让你直接嵌套 jar。通过约定目录结构(layers.idx),约定类路径索引(classpath.idx)等方式,定义了SpringBoot的“uber jar”目录结构。通过扩展JarFile、自定义JarFileArchive归档模型,扩展官方JarURLConnection的jar读取器(JarURLConnection),扩展官方的URLClassLoader类加载器(LaunchedURLClassLoader),自定义引导类作为可执行 jar 的主入口(JarLauncher)等一系列扩展,实现了对嵌套jar的读取和类加载支持。

  • SpringBoot关于可执行的“uber jar”的工作原理的介绍文档
  • SpringBoot 为 Maven 和 Gradle 提供了构建工具插件

三、SpringBoot的Executable Jars

1.核心支持模块(spring-boot-loader)

spring-boot-loader模块使 Spring Boot 支持可执行的 jar 和 war 文件。 如果您使用 Maven 插件或 Gradle 插件,则会自动生成可执行 jar,您通常不需要知道它们工作原理的详细信息。如果需要了解改模块的代码实现,需要在SpringBoot项目中引入如下依赖并下载源码资源:

<dependencies><dependency><groupId>org.springframework.boot