Springboot jar是如何启动的
可执行的jar 启动
使用java jar 命令生成jar包,会自动生成 META-INF/MANIFEST.MF
spring-boot3-graavm-image>jar cvfe aaa.jar pr.iceworld.fernando.springboot3.image.MainApplication ./target/classes
会生成
Manifest-Version: 1.0
Created-By: 17.0.5 (BellSoft)
Main-Class: pr.iceworld.fernando.springboot3.image.MainApplication
指定了Main-Class
为 pr.iceworld.fernando.springboot3.image.MainApplication
Springboot 工程jar是如何启动的
会生成一个${工程名}-${工程版本}.jar
里面包含jar所需要的META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.3.0
Build-Jdk-Spec: 17
Implementation-Title: spring-boot3-graavm-image
Implementation-Version: 3.0.0
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: pr.iceworld.fernando.springboot3.image.MainApplication
Spring-Boot-Version: 3.0.0
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
spring-boot-maven-plugin 会帮我们指定
Main-Class
为 org.springframework.boot.loader.JarLauncher
Start-Class
为 pr.iceworld.fernando.springboot3.image.MainApplication
JarLauncher
就是 springboot jar 的启动入口类
public class JarLauncher extends ExecutableArchiveLauncher {
// ...
public static void main(String[] args) throws Exception {
// 最终调用 Launcher#launcher(String[])
new JarLauncher().launch(args);
}
}
ExecutableArchiveLauncher
的父类是 Launcher
public abstract class ExecutableArchiveLauncher extends Launcher {
// ...
private static final String START_CLASS_ATTRIBUTE = "Start-Class";
// ...
@Override
protected String getMainClass() throws Exception {
Manifest manifest = this.archive.getManifest();
String mainClass = null;
if (manifest != null) {
mainClass = manifest.getMainAttributes().getValue(START_CLASS_ATTRIBUTE);
}
if (mainClass == null) {
throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this);
}
return mainClass;
}
// ...
}
public abstract class Launcher {
// ...
protected void launch(String[] args) throws Exception {
if (!isExploded()) {
// 注册能解析spring boot jar 的Handler
JarFile.registerUrlProtocolHandler();
}
// 创建 Springboot 自定义 ClassLoader
ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator());
String jarMode = System.getProperty("jarmode");
// 默认使用 getMainClass() 获取 `META-INF/MANIFEST.MF`Start-Class` 值
String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass();
// 反射调用应用程序主类 `Start-Class`值
launch(args, launchClass, classLoader);
}
// ...
protected void launch(String[] args, String launchClass, ClassLoader classLoader) throws Exception {
Thread.currentThread().setContextClassLoader(classLoader);
createMainMethodRunner(launchClass, args, classLoader).run();
}
// ...
protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
return new MainMethodRunner(mainClass, args);
}
// ...
protected boolean isExploded() {
return false;
}
// ...
}
public class MainMethodRunner {
private final String mainClassName;
private final String[] args;
public MainMethodRunner(String mainClass, String[] args) {
this.mainClassName = mainClass;
this.args = (args != null) ? args.clone() : null;
}
// 通过反射调用 `Start-Class`
public void run() throws Exception {
Class<?> mainClass = Class.forName(this.mainClassName, false, Thread.currentThread().getContextClassLoader());
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.setAccessible(true);
mainMethod.invoke(null, new Object[] { this.args });
}
}