SpringBoot的启动引导类真的是XXApplication吗?

1. 引言

SpringBoot项目中的启动类,一般都是XXApplication,例如StatsApplication,UnionApplication。每个项目的启动类名称都不一样。但是它的启动类真的是XXApplication吗?

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

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

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

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

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

重要信息如下

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

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

下面浏览下JarLauncher

3. 浏览JarLauncher

3.1 找到JarLauncher

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

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

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

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

1<dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-loader</artifactId> 4 <scope>provided</scope> 5</dependency>

3.2.JarLauncher说明

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

简化层次关系为:

JarLauncher#launch代码如下

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

聚句解析

1,.JarFile.registerUrlProtocolHandler();

Spring Boot生成的FAT jar,在被java -jar 引导时,其内部的jar文件无法被sun.net. www.protocol .jar.Handler处理。

所以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覆写了。其实现如下:

1static final String BOOT_INF_CLASSES = "BOOT-INF/classes/"; 2 3static final String BOOT_INF_LIB = "BOOT-INF/lib/"; 4@Override 5protected boolean isNestedArchive(Archive.Entry entry) { 6 if (entry.isDirectory()) { 7 return entry.getName().equals(BOOT_INF_CLASSES); 8 } 9 return entry.getName().startsWith(BOOT_INF_LIB); 10}

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

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

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

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

查看createMainMethodRunner的run方法,如下:

1public class MainMethodRunner { 2 // 省略部分代码 3 public void run() throws Exception { 4 Class<?> mainClass = Thread.currentThread().getContextClassLoader() 5 .loadClass(this.mainClassName); 6 Method mainMethod = 7 mainClass.getDeclaredMethod("main", String[].class); 8 mainMethod.invoke(null, new Object[] { this.args }); 9 } 10}

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

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

4.总结

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

在JarLauncher内部通过反射调用XXApplication类的main方法。

具体实现位于 MainMethodRunner中。

5.写在最后

在解决这个问题,查找资料的过程中,发现小马哥写了一本《SpringBoot的编程思想》。

我欣喜的买了一本,阅读了一遍。它详细介绍了SpringBoot的原理。

其中有个章节就是介绍JarLauncher。推荐这本书!

我是自来水,没有广告费。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

SpringBoot整合Redis乱码原因及解决方案

问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa

Android So动态加载 优雅实现与原理分析

背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我