jar包结构
.
├── BOOT-INF
│ ├── classes
│ │ └── me
│ │ └── uc
│ │ └── launcher
│ │ └── TestApp.class
│ └── lib
│ ├── classmate-1.5.1.jar
│ ├── hibernate-validator-6.0.18.Final.jar
│ ├── jackson-annotations-2.10.2.jar
│ ├── jackson-core-2.10.2.jar
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
│ └── com.uc.spring.showcase
│ └── launcher-test
│ ├── pom.properties
│ └── pom.xml
└── org
└── springframework
└── boot
└── loader
├── archive
│ ├── Archive.class
│ ├── Archive
E
n
t
r
y
.
c
l
a
s
s
│
├
─
─
A
r
c
h
i
v
e
Entry.class │ ├── Archive
Entry.class│├──ArchiveEntryFilter.class
│ ├── ExplodedArchive$1.class
BOOT-INF下为用户类和相关依赖
查看jar包中的Manifest
Manifest-Version: 1.0
Implementation-Title: launcher-test
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: me.uc.launcher.TestApp
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.5.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher
org.springframework.boot.loader.JarLauncher#main
public static void main(String[] args) throws Exception {
new JarLauncher().launch(args);
}
org.springframework.boot.loader.Launcher#launch(java.lang.String[])
/**
* 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 {
JarFile.registerUrlProtocolHandler();
ClassLoader classLoader = createClassLoader(getClassPathArchives());
//获取启动类Start-Class: me.uc.launcher.TestApp
launch(args, getMainClass(), classLoader);
}
@Override
protected String getMainClass() throws Exception {
Manifest manifest = this.archive.getManifest();
String mainClass = null;
if (manifest != null) {
//从Manifest中查找Start-Class
mainClass = manifest.getMainAttributes().getValue("Start-Class");
}
if (mainClass == null) {
throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this);
}
return mainClass;
}
/**
* 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 {
Thread.currentThread().setContextClassLoader(classLoader);
createMainMethodRunner(mainClass, args, classLoader).run();
}
通过反射调用Start-Class main方法
org.springframework.boot.loader.MainMethodRunner#run
public void run() throws Exception {
Class<?> mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[] { this.args });
}
参考
https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/appendix-executable-jar-format.html#executable-jar