引言

SpringBoot项目中的启动类,一般都是XXApplication,例如「StatsApplication」「UnionApplication」

每个项目的启动类名称都不一样。但是它的启动类真的是XXApplication吗?

META-INF/****Manifest.mf文件

jar文件实际上是class文件的zip压缩存档。jar并不能表达应用程序的便签信息.

「META-INF/Manifest.mf文件提供存档的便签信息.」

Manifest.mf有 「Main-Class,用来标明jar文件的入口类。」

解压jar包,查看META-INF/Manifest.mf过程如下:

重要信息如下

Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.shanyuan.StatsApplication

也就是说:「org.springframework.boot.loader.JarLauncher 是 SpringBoot 的启动类!」

下面浏览下 JarLauncher

浏览JarLauncher

3.1 找到JarLauncher

进入IDEA,Ctrl+N查找JarLauncher,竟然找不到!!

进入 https://search.maven.org/classic/#advancedsearch 查询JarLauncher

在查询结果找到spring下的项目

确定 JarLauncher 位于 spring-boot-loader 下。为了方便查看源码,在 pom 中引入

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
<scope>provided</scope>
</dependency>

3.2.JarLauncher说明

JarLauncher作为引导类 ,当调用java -jar 命令时,将调用 main 方法,实际上调用的是 「JarLauncher#launch」方法,该方法继承于 org.springframework.boot.loader.Launcher

简化层次关系为:

JarLauncher#launch代码如下

protected void launch(String[] args) throws Exception {
JarFile.registerUrlProtocolHandler();
ClassLoader classLoader = createClassLoader(getClassPathArchives());
launch(args, getMainClass(), classLoader);
}

「聚句解析」

「1,.JarFile.registerUrlProtocolHandler();」

Spring Boot 生成的 FAT jar,在被 java -jar 引导时,其内部的 jar 文件无法被 sun.net.www.protocol.jar.Handler 处理。微信公众号搜索, [Java学习之道] ,回复 '福利' 2T 资料等你来拿~

所以 SpringBoot 实现了,org.springframework.boot.loader.jar.Handler

JarFile.registerUrlProtocolHandler(), 就注册 org.springframework.boot.loader.jar.Handler

「2.ClassLoader classLoader = createClassLoader(getClassPathArchives());」

创建ClassLoader。

getClassPathArchives 核心判断是 isNestedArchive 方法。

isNestedArchive 被 JarLauncher 覆写了。其实现如下:

static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";

static final String BOOT_INF_LIB = "BOOT-INF/lib/";
@Override
protected boolean isNestedArchive(Archive.Entry entry) {
if (entry.isDirectory()) {
return entry.getName().equals(BOOT_INF_CLASSES);
}
return entry.getName().startsWith(BOOT_INF_LIB);
}

也就是说,只要 「满足以BOOT-INF/classes/和BOOT-INF/lib/都是classLoader加载」的范围。

解压的jar,查看也与只对应

3. launch(args, getMainClass(), classLoader);

protected void launch(String[] args, String mainClass,
ClassLoader classLoader)
throws Exception {
Thread.currentThread().setContextClassLoader(classLoader);
createMainMethodRunner(mainClass, args, classLoader).run();
}

查看 createMainMethodRunner 的 run 方法,如下:

public class MainMethodRunner {
// 省略部分代码
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 });
}
}

其中 mainClass,来自 /META-INF/MANIFEST.MF 中的 Start-Class 属性。

「即,JarLauncher 是同进程内,通过反射调用 Start-Class 对应类,即 XXXApplication 的 main 方法。」

4.总结

SpringBoot 项目的实际启动类是 org.springframework.boot.loader.JarLauncher

「在 JarLauncher 内部通过反射调用 XXApplication 类的 main 方法。具体实现位于 MainMethodRunner中。」

写在最后

欢迎大家关注我的公众号【风平浪静如码】,海量Java相关文章,学习资料都会在里面更新,整理的资料也会放在里面。

觉得写的还不错的就点个赞,加个关注呗!点关注,不迷路,持续更新!!!

震惊!你还不知道SpringBoot真正的启动引导类的更多相关文章

  1. SpringBoot是如何启动的?

    本文是通过查看SpringBoot源码整理出来的SpringBoot大致启动流程,整体大方向是以简单为出发点,不说太多复杂的东西,内部实现细节本文不深扣因为每个人的思路.理解都不一样,我个人看的理解跟 ...

  2. 【玩转SpringBoot】通过事件机制参与SpringBoot应用的启动过程

    生命周期和事件监听 一个应用的启动过程和关闭过程是归属到“生命周期”这个概念的范畴. 典型的设计是在启动和关闭过程中会触发一系列的“事件”,我们只要监听这些事件,就能参与到这个过程中来. 要想监听事件 ...

  3. SpringBoot项目快速启动停止脚本

    SpringBoot项目快速启动停止脚本 1.在jar包同级目录下,创建 app.sh #!/bin/bash appName=`ls|grep .jar$` if [ -z $appName ] t ...

  4. 【玩转SpringBoot】SpringBoot应用的启动过程一览表

    SpringBoot应用的启动方式很简单,就一行代码,如下图01: 其实这行代码背后主要执行两个方法,一个是构造方法,一个是run方法. 构造方法主要内容就是收集一些数据,和确认一些信息.如下图02: ...

  5. JDK15就要来了,你却还不知道JDK8的新特性!

    微信搜「烟雨星空」,白嫖更多好文. 现在 Oracle 官方每隔半年就会出一个 JDK 新版本.按时间来算的话,这个月就要出 JDK15 了.然而,大部分公司还是在使用 JDK7 和 8 . 之前去我 ...

  6. SpringBoot学习之启动探究

    SpringApplication是SpringBoot的启动程序,我们通过它的run方法可以快速启动一个SpringBoot应用.可是这里面到底发生了什么?它是处于什么样的机制简化我们程序启动的?接 ...

  7. spring-boot 根据环境启动

    spring-boot 根据环境启动: java -jar spring-boot--config--SNAPSHOT.jar --spring.profiles.active=prod

  8. 3.Springboot之修改启动时的默认图案Banner

    一.SpringBoot的默认启动图案 在SpringBoot启动的时候,默认的会展示出一个spring的logo,这个图案我们用户是可以自定义的 二.自定义启动图案 方法一: Application ...

  9. springboot项目启动无法访问到controller原因之一:引导类位置有问题

    新建的springboot项目启动后,无法访问到controller 页面是404错误 查看项目结构,发现是新建工程的启动类位置有问题,controller类应该位于引导类的同级包或者子级包中.需要将 ...

随机推荐

  1. jQurey轮播插件slides简单使用教程

    动态演示地址: http://www.zqunyan.com/zgproduction/slidesjs/index.html 简介就不多说了,网上有很多,复制粘贴没意义,会想到用这个插件就代表已经了 ...

  2. Go-常量-const

    常量:只能读,不能修改,编译前就是确定的值 关键字: const 常量相关类型:int8,16,32,64 float32,64 bool string 可计算结果数学表达式 常量方法 iota pa ...

  3. 008 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 02 Java 中的关键字

    008 01 Android 零基础入门 01 Java基础语法 02 Java常量与变量 02 Java 中的关键字 关键字 关键字就是一些有特殊意义的词 之前学习的程序中涉及到的关键字 Java中 ...

  4. 【漏洞复现】PHPmyadmin 4.8.1后台Getshell新姿势

    原文地址:https://mp.weixin.qq.com/s/HZcS2HdUtqz10jUEN57aog 早上看到群里在讨论一个新姿势,phpmyadmin后台getshell,不同于以往需要知道 ...

  5. NOIP提高组2018 D1T3 【赛道修建】

    颓了好几天,终于把这到题处理了一下. 话说,其实我考场上想出正解了,但是手残,算复杂度的时候多按了一个零,导致算出来是1亿多的复杂度,都不敢打...就把部分分都捡了一下... 题目描述: C 城将要举 ...

  6. 许嵩新歌《放肆》发布 && 递归 + Stream+Lambda相遇成树

    一.<放肆>如约而至 今早5:00在迷迷糊糊中醒来,打开手机一看,许嵩又发新歌了,名字叫做<放肆>,澎湃的旋律,依旧古典高雅的用词,这个大男孩,已经不像12年那时候发些伤感非主 ...

  7. C# 用IrisSkin4.dll美化你的WinForm

    如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! --------------------------- ...

  8. 每日一题 LeetCode 486. 预测赢家 【递推】【前缀和】【动态规划】

    题目链接 https://leetcode-cn.com/problems/predict-the-winner/ 题目说明 题解 主要方法:递推:动态规划:前缀和 解释说明: 求前缀和 pre_nu ...

  9. python中的对文件的读写

    简单的实例 open函数获取文件,w是写权限,可以对文件进行io操作 file=open('C:/Users/Administrator/Desktop/yes.txt','w') file.writ ...

  10. 题解:CF593D Happy Tree Party

    题解:CF593D Happy Tree Party Description Bogdan has a birthday today and mom gave him a tree consistin ...