一、讲述
1.SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包。
2.Spring Boot应用打包之后,生成一个Fat jar(jar包中包含jar),包含了应用依赖的jar包和Spring Boot loader相关的
类。
3.java -jar会去找jar中的manifest文件,在那里面找到真正的启动类(Main-Class);
4.Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载boot-lib下面的jar,并以一个新线程启动应用的启动类的Main函数(找到manifest中的Start-Class)。
二、原理
SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包。pom文件配置如下
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version>
</plugin>
插件spring-boot-maven-plugin,提供了7个maven goal
- build-image: 将程序使用 buildpack 打包进容器镜像中。
- build-info:生成项目的构建信息文件 build-info.properties
- help:显示帮助信息。调用mvn spring-boot:help -Ddetail=true -Dgoal=以显示参数详细信息。
- repackage:可生成可执行的jar包或war包。插件的核心goal。
- run:运行 Spring Boot 应用
- start:在集成测试阶段,控制生命周期
- stop:在集成测试阶段,控制生命周期
2、通过mvn package命令,Maven首先会按照标准流程构建项目,随后spring-boot-maven-plugin会执行repackage目标,该目标会重新包装已生成的标准JAR文件,将其转换为包含所有依赖项和适当的启动器信息的Fat JAR。这样生成的JAR可以直接通过java -jar命令启动。jar内部目录如下
- META-INF/: 包含MANIFEST.MF文件和其他元数据信息,其中Main-Class属性指向Spring Boot的启动类加载器。
- BOOT-INF/classes/: 存放项目自身的类文件和资源文件。
- BOOT-INF/lib/: 放置所有依赖的jar包,包括Spring Boot starter依赖以及其他第三方库。(如果项目中有静态资源文件,也会在BOOT-INF下有对应的static、templates等目录)
3、Spring Boot启动器与Loader机制与MANIFEST.MF文件
Spring Boot应用的jar包可以直接运行主要依赖于它的启动器以及Loader机制,而对于Loader机制主要利用MANIFEST.MF文件以及其内部类加载逻辑。
MANIFEST.MF是JAR文件内的一个标准元数据文件,它包含了关于JAR包的基本信息和运行指令。在jvm规范单中java -jar指令中会规范一个main方法,而这个main方法就在MANIFEST.MF文件中的Main-Class属性,这个类通常是org.springframework.boot.loader.JarLauncher或其他由Spring Boot提供的启动器类。Start-Class属性是启动应用的main方法。JarLauncher会通过一个子线程启动Start-Class中的main方法
4、JarLauncher执行流程
JarLauncher 入口 main 方法
public static void main(String[] args) throws Exception {// launch 方法是调用父类 Launcher 的 launch 方法new JarLauncher().launch(args);
}
这里是加载清单文件的中的配置
/*** Launch the application. This method is the initial entry point that should be* called by a subclass {@code public static void main(String[] args)} method.启动一个应用,这个方法应该被初始的入口点,这个入口点应该是一个Launcher的子类的 public static void main(String[] args)这样的方法调用* @param args the incoming arguments* @throws Exception if the application fails to launch*/protected void launch(String[] args) throws Exception {if (!isExploded()) {// 注册一些 URL的属性JarFile.registerUrlProtocolHandler();}// 创建类加载器(LaunchedURLClassLoader),加载得到集合要么是BOOT-INF/classes/,或者BOOT-INF/lib/的目录或者是他们下边的class文件或者jar依赖文件ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator());String jarMode = System.getProperty("jarmode");String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass();// 执行应用的main方法launch(args, launchClass, classLoader);}