Launcher实现原理
在上节内容中,我们得知 jar 包 Main-Class 指定入口程序为 Spring Boot 提供的 L auncher(JarL auncher),并不是我们在 Spring Boot 项目中所写的入口类。那么,Launcher 类又是如何实现项目的启动呢?本节带大家了解其相关原理。
Launcher 类的具体实现类有 3 个: JarL auncher、Warl _auncher 和 PropertiesLauncher,我们这里主要讲解 JarLauncher 和 WarLauncher。首先,以 JarL auncher 为例来解析说明Spring Boot 基于 Launcher 来实现的启动过呈。
JarLauncher
在了解 JarL .auncher 的实现原理之前,先来看看 JarL auncher 的源码。
public class JarLauncher extends ExecutableArchiveLauncher
static final String BOOT_ INF_ CLASSES = "BOOT- INF/classes/";
static final String BOOT_ INF_ LIB = "B0OOT-INF/lib/";
//省略构造方法
@Override
protected boolean isNestedArchive(Archive. Entry entry) {
if (entry. isDirectory())
return entry. getName() . equals(B0OT_ _INF_ CLASSES);
return entry . getName() . startsWith(BOOT_ INF_ LIB);
public static void main(String[] args) throws Exception {
new JarLauncher(). launch(args);
}
}
JarLauncher 类结构非常简单,它继承了抽象类 ExecutableArchiveLauncher,而抽象类又继承了抽象类 Launcher。
JarLauncher 中定义了两个常量: BOOT_ INF_ _CLASSES 和 BOOT_ _INF_ LIB,它们分别定义了业务代码存放在 jar 包中的位置( BOOT-INF/classes/)和依赖 jar 包所在的位置(BOOT-INF/ib/) 。
JarLauncher 中提供了一-个 main 方法,即入口程序的功能,在该方法中首先创建了 JarLauncher 对象,然后调用其 launch 方法。大家都知道,当创建子类对象时,会先调用父类的构造方法。因此,父类 ExecutableArchiveL auncher 的构造方法被调用。
public abstract class ExecutableArchiveL auncher extends L auncher {
private final Archive archive;
public ExecutableArchiveLauncher() {
try {
this.archive = createArchive();
} catch (Exception ex) {
throw new IllegalStateException(ex);}
}
}
在 ExecutableArchiveLauncher 的构造方法中仅实现了父类 Launcher 的 createArchive 方法的调用和异常的抛出。Launcher 类中 createArchive 方法源代码如下。
protected final Archive createArchive() throws Exception {
//通过获得当前 Class 类的信息,查找到当前归档文件的路径
ProtectionDomain protectionDomain = getClass() . getProtectionDomain();
CodeSource codeSource = protectionDomain. getCodeSource();
URI location = (codeSource != nu1l) ? codeSource . getLocation() . toURI()
null;
String path = (location != null) ? location. getSchemeSpecificPart() : n
ul1;
if (path == null) {
throw new IllegalStateException("Unable to determine code source ar
chive");
//获得路径之后,创建对应的文件,并检查是否存在
File root = new File(path);
if (!root . exists()) {
throw new IllegalStateException("Unable to determine code source ar
chive from”+ root);
//如果是目录,则创建 ExplodedArchive, 否则创建