SpringBoot的 jar 可以直接运行

SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

打包完生成的executable-jar-1.0-SNAPSHOT.jar内部的结构如下

根目录
    |-- BOOT-INF        
    	|-- classes        
    	|-- lib
    |-- META-INF
    |-- org
  • BOOT-INF 目录
  • classes 目录中存放项目代码对应的 .class文件
  • lib 目录中存放项目相关的依赖包,依赖包以 jar包 的方式存放(jar文件中存放jar文件,有个专门称呼叫 “FatJar”
  • META-INF
  • 存放清单文件,其内容描述当前可执行 jar 包的基本信息
  • 其中,有两个主要的描述信息:
  • Main-Class
  • 描述 jar包 的入口文件(main 方法所在的类)
  • Spring 框架固定是 org.springframework.boot.loader.JarLauncher
  • 定义完此属性后,一定要有一个换行
  • Start-Class
  • 描述自定义 main 方法的全称
  • org
  • 存放了一些打包 SpringBoot 项目后的相关启动类
  • 由于 SpringBoot 基于管理及安全性的考虑,打包使用 “项目代码与依赖包分离” 的方式(不同于以前将所有依赖包中的 .class 文件与项目的 .class 文件合并到一起的方式),因此打包后的 jar/war 包中依然包含了依赖的 jar 包,不符合 jar包 的规范,依赖的 jar包 无法通过默认的加载器进行加载
  • 为了规避 jar文件规范,SpringBoot 使用自定义加载器去加载整个项目,于是入口就不再是编写项目时的 main 方法,而是使用 org.springframework.boot.loader.JarLauncher 类,在启动的时候创建自定义加载器去加载项目中的所有类
  • 因此,打包后的 SpringBoot 项目,只有 org 文件夹中的类的类加载器是 AppClassLoaderBOOT-INF 文件夹中的类和依赖包的加载器是 LaunchedURLClassLoader

war包的结构跟jar包结构差不多,只是多了几个目录(如 “WEB-INF/” 等)。

Spring Boot Loader的作用

SpringBoot在可执行jar包中定义了自己的一套规则,比如第三方依赖jar包在/lib目录下,jar包的URL路径使用自定义的规则并且这个规则需要使用org.springframework.boot.loader.jar.Handler处理器处理。它的Main-Class使用JarLauncher,如果是war包,使用WarLauncher执行。这些Launcher内部都会另起一个线程启动自定义的SpringApplication类。

这些特性通过 spring-boot-maven-plugin 插件打包完成。