Spring Boot Fat Jar 启动原理
in Java with 3 comment

Spring Boot Fat Jar 启动原理

in Java with 3 comment


开始学习及使用 Spring Boot 的时候,通常都编写过以下代码:

package com.example.myapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);


接着通过 Gradle 或者 Maven 构建工具打包得到文件app.jar,然后输入以下命令启动:

java -jar app.jar

这里读者可能会误以为 JVM 是直接调用的 Application#main 函数,然后开始执行 SpringApplication.run(Application.class, args);



首先我们分析一下 java -jar 这个操作到底做了什么。

查询 java 命令手册之后,在描述区有这么一句:

By default, the first argument that is not an option of the java command is the fully qualified name of the class to be called.
If the -jar option is specified, its argument is the name of the JAR file containing class and resource files for the application. The startup class must be indicated by the Main-Class manifest header in its source code.

重点在于最后一句:启动类必须指定在 Manifest 清单中的 Main-Class 头中。

当然,直接查看 -jar option 也能找打类似的描述:

-jar filename
    Executes a program encapsulated in a JAR file. The filename argument is the name of a JAR file with a manifest that contains
    a line in the form Main-Class:classname that defines the class with the public static void main(String[] args) method that
    serves as your application's starting point.
    When you use the -jar option, the specified JAR file is the source of all user classes, and other class path settings are

至此我们已经了解到执行 java -jar app.jar 的第一步是寻找 Manifest 清单中的 Main-Class 头,找到启动类之后才进行调用 #main 函数。

解压 app.jar

app.jar 是经过 Gradle 或者 Mavenspring boot plugin 插件特殊处理。解压结果如下:

 |  +-springframework
 |     +-boot
 |        +-loader
 |           +-<spring boot loader classes>
    |  +-example
    |     +-myapplication
    |        +-Application.class
    |        +-Other classes...

可以从以下链接找到 jar 文件的规格要求。


Manifest-Version: 1.0
Implementation-Title: Example Application
Implementation-Version: 1.1.0
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.example.myapplication.Application
Spring-Boot-Version: 2.2.1.RELEASE
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/

该文件指定 org.springframework.boot.loader.JarLauncherMain-Class,也就意味着通过 java -jar app.jar 命令运行后首先执行的应该是 JarLauncher#main

JarLauncher 文件可以在以下链接找到。


JarLauncherspring boot loader 子模块中的一个类,内容如下:

package org.springframework.boot.loader;

import org.springframework.boot.loader.archive.Archive;

 * {@link Launcher} for JAR based archives. This launcher assumes that dependency jars are
 * included inside a {@code /BOOT-INF/lib} directory and that application classes are
 * included inside a {@code /BOOT-INF/classes} directory.
 * @author Phillip Webb
 * @author Andy Wilkinson
 * @since 1.0.0
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) {

	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);

JarLauncher#main 中调用的 Launcher#launch(args) 实际上是调用父类 org.springframework.boot.loader.Launcher#launch(args) 方法。

org.springframework.boot.loader.Launcher 可以在以下链接中找到。

Launcher 的主要的方法如下:

 * 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.
 * @param args the incoming arguments
 * @throws Exception if the application fails to launch
protected void launch(String[] args) throws Exception {
	ClassLoader classLoader = createClassLoader(getClassPathArchives());
	launch(args, getMainClass(), classLoader);

 * Launch the application given the archive file and a fully configured classloader.
 * @param args the incoming arguments
 * @param mainClass the main class to run
 * @param classLoader the classloader
 * @throws Exception if the launch fails
protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
	createMainMethodRunner(mainClass, args, classLoader).run();


直到最后一步执行完成,才开始真正执行 Application@main 函数,才正式进入 Spring Boot 的初始化。