学习第四篇:【SpringBoot-Labs】Jar 启动原理

本周(8.21-8.27)将学习芋道 Spring Boot的以下文章:
8.21: 快速入门
**8.22:**Spring Boot 自动配置原理 、Jar 启动原理
8.23:调试环境、 热部署入门、消除冗余代码 Lombok 入门
8.24:对象转换 MapStruct 入门、SpringMVC 入门
8.25: WebFlux 入门、 分布式 Session 入门
8.26:API 接口文档 Swagger 入门、API 接口文档 Swagger Starter 入门
8.27:参数校验 Validation 入门、WebSocket 入门

芋道 Spring Boot Jar 启动原理

  • Spring Boot 提供了 Maven 插件 spring-boot-maven-plugin,可以方便的将 Spring Boot 项目打成 jar 包或者 war 包。

  • Jar包的结构组成

    • META-INF 目录:通过 MANIFEST.MF 文件提供 jar 包的元数据,声明了 jar 的启动类。

    • org 目录:为 Spring Boot 提供的 spring-boot-loader 项目,它是 java -jar 启动 Spring Boot 项目的秘密所在,也是稍后我们将深入了解的部分。

      Spring Boot Loader provides the secret sauce that allows you to build a single jar file that can be launched using java -jar. Generally you will not need to use spring-boot-loader directly, but instead work with the Gradle or Maven plugin.

    • BOOT-INF/lib 目录:我们 Spring Boot 项目中引入的依赖jar 包们。spring-boot-loader 项目很大的一个作用,就是解决 jar 包里嵌套 jar 的情况,如何加载到其中的类。

      • spring-boot-loader 项目需要解决两个问题:
        • 第一,如何引导执行我们创建的 Spring Boot 应用的启动类,例如上述图中的 Application 类。
        • 第二,如何加载 BOOT-INF/class 目录下的类,以及 BOOT-INF/lib 目录下内嵌的 jar 包中的类。
    • BOOT-INF/classes 目录:我们在 Spring Boot 项目中 Java 类所编译的 .class、配置文件等等。

  • META-INF/MANIFEST.MF 文件,里面的内容如下:

    Manifest-Version: 1.0
    Implementation-Title: lab-39-demo
    Implementation-Version: 2.2.2.RELEASE
    Start-Class: cn.iocoder.springboot.lab39.skywalkingdemo.Application
    Spring-Boot-Classes: BOOT-INF/classes/
    Spring-Boot-Lib: BOOT-INF/lib/
    Build-Jdk-Spec: 1.8
    Spring-Boot-Version: 2.2.2.RELEASE
    Created-By: Maven Archiver 3.4.0
    Main-Class: org.springframework.boot.loader.JarLauncher
    
  • 实际是一个 Properties 配置文件,每一行都是一个配置项目。重点来看看两个配置项:

    • Main-Class 配置项:Java 规定的 jar 包的启动类,这里设置为 spring-boot-loader 项目的 JarLauncher 类,进行 Spring Boot 应用的启动。
    • Start-Class 配置项:Spring Boot 规定的启动类,这里设置为我们定义的 Application 类。

    小知识补充:为什么会有 Main-Class/Start-Class 配置项呢?因为我们是通过 Spring Boot 提供的 Maven 插件 spring-boot-maven-plugin 进行打包,该插件将该配置项写入到 MANIFEST.MF 中,从而能让 spring-boot-loader 能够引导启动 Spring Boot 应用。

    • 直接运行Start-Class 配置项的主启动类(main函数)是无法启动的(提示找不到或无法加载主类),主要是因为打包成的jar的不符合java默认加载jar包的规则(/WEB-INF/classes下的class文件,而Start-Class的Aplication类被打包在 BOOT-INF/classes下,其次Java 规定可执行器的 jar 包禁止嵌套其它 jar 包,而maven项目需要加载BOOT-INF/lib 目录下Spring Boot 应用依赖的所有 jar 包),所以需要通过spring-boot-loader 项目自定义实现了 ClassLoader 实现类 LaunchedURLClassLoader,支持加载 BOOT-INF/classes 目录下的 .class 文件,以及 BOOT-INF/lib 目录下的 jar 包。
  • JarLauncher 类是针对 Spring Boot jar 包的启动类,整体类图如下所示:

    JarLauncher 类图

    代码如下:

    public class JarLauncher extends ExecutableArchiveLauncher {
    
    	static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
    
    	static final String BOOT_INF_LIB = "BOOT-INF/lib/";
    
    	public JarLauncher() {
    	}
    
    	protected JarLauncher(Archive archive) {
    		super(archive);
    	}
    
    	@Override
    	protected boolean isNestedArchive(Archive.Entry entry) {
    		if (entry.isDirectory()) {
    			return entry.getName().equals(BOOT_INF_CLASSES);
    		}
    		return entry.getName().startsWith(BOOT_INF_LIB);
    	}
    
    	public static void main(String[] args) throws Exception {
    		new JarLauncher().launch(args);
    	}
    
    }
    

    通过 #main(String[] args) 方法,创建 JarLauncher 对象,并调用其 #launch(String[] args) 方法进行启动。整体的启动逻辑,其实是由父类 Launcher 所提供。

  • 简单来说,就是做一个可以读取 jar 包中类的加载器,保证 BOOT-INF/lib 目录下的类和 BOOT-classes 内嵌的 jar 中的类能够被正常加载到,之后执行 Spring Boot 应用的启动。

  • LaunchedURLClassLoaderspring-boot-loader 项目自定义的类加载器,实现对 jar 包中 META-INF/classes 目录下的META-INF/lib 内嵌的 jar 包中的加载

  • 总体来说,Spring Boot jar 启动的原理是非常清晰的,整体如下图所示:

    Spring Boot  启动原理

红色部分,解决 jar 包中的类加载问题:

  • 通过 Archive,实现 jar 包的遍历,将 META-INF/classes 目录和 META-INF/lib 的每一个内嵌的 jar 解析成一个 Archive 对象。
  • 通过 Handler,处理 jar: 协议的 URL 的资源读取,也就是读取了每个 Archive 里的内容。
  • 通过 LaunchedURLClassLoader,实现 META-INF/classes 目录下的类和 META-INF/classes 目录下内嵌的 jar 包中的类的加载。具体的 URL 来源,是通过 Archive 提供;具体 URL 的读取,是通过 Handler 提供。

橘色部分,解决 Spring Boot 应用的启动问题:

当然,上述的一切都是通过 Launcher 来完成引导和启动,通过 MANIFEST.MF 进行具体配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值