Spring Boot项目的真实程序入口

2023-11-18

基于 spring-boot-start开发的项目,其程序入口并不是我们开发的业务代码中定义了 main 函数的类,而是 Spring Boot 定义的 JarLauncher 类(下文源码反编译自 spring-boot-loader-1.5.8.RELEASE.jar)。

通常使用 spring boot 进行开发时,会定义类似以下程序入口

@SpringBootApplication
/**
 * This @SpringBootApplication is a convenience annotation that adds all of the following:
 * @Configuration tags the class as a source of bean definitions for the application context.
 * @EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
 * @EnableWebMvc Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
 * @ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
 * */
@ServletComponentScan
@EnableTransactionManagement
@EnableAsync(proxyTargetClass = true)
public class KiApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(KiApplication.class, args);
    }
}

然后,通过增加 maven 插件 spring-boot-maven-plugin 可以将开发好的项目打包为可执行的 *.jar ,虽然在开发的代码中定义了main函数,但是不要以为程序就是从这个类开始执行的。因为,如果打开打包的 *.jar 中 /META-INF/MANIFEST.MF 文件查看,就会发现真实的入口类并不是我们定义了main函数的类,而是 org.springframework.boot.loader.JarLauncher 。如下,Main-Class 定义 jar 的入口类,另外扩展了 Start-Class 定义启动类,这才是我们业务代码中定义了main函数的类。

Manifest-Version: 1.0
Implementation-Title: kiff-starter
Implementation-Version: 1.0-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: zouzhiyuan
Implementation-Vendor-Id: *.*.*
Spring-Boot-Version: 1.5.8.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: *.*.*.KiApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.0.5
Build-Jdk: 1.8.0_51
Implementation-URL: http://projects.spring.io/spring-boot/kiff-starter
 /
进一步查看 JarLauncher 类的源码可以发现,该类声明的 main 函数 调用了父类的 launch() 方法,并且将 args 参数进行透传。

package org.springframework.boot.loader;

import org.springframework.boot.loader.ExecutableArchiveLauncher;
import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.archive.Archive.Entry;

public class JarLauncher extends ExecutableArchiveLauncher {
    static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
    static final String BOOT_INF_LIB = "BOOT-INF/lib/";

    public JarLauncher() {
    }

    protected JarLauncher(Archive archive) {
        super(archive);
    }

    protected boolean isNestedArchive(Entry entry) {
        return entry.isDirectory()?entry.getName().equals("BOOT-INF/classes/"):entry.getName().startsWith("BOOT-INF/lib/");
    }

    public static void main(String[] args) throws Exception {
        (new JarLauncher()).launch(args);
    }
}

继续查看 JarLauncher 类继承的 ExecutableArchiveLauncher 类,源代码如下,这个类中的 getMainClass() 方法实际上是在找 MANIFEST.MF 文件中定义的 Start-Class

public abstract class ExecutableArchiveLauncher extends Launcher {
    private final Archive archive;

    public ExecutableArchiveLauncher() {
        try {
            this.archive = this.createArchive();
        } catch (Exception var2) {
            throw new IllegalStateException(var2);
        }
    }

    protected ExecutableArchiveLauncher(Archive archive) {
        this.archive = archive;
    }

    protected final Archive getArchive() {
        return this.archive;
    }

    protected String getMainClass() throws Exception {
        Manifest manifest = this.archive.getManifest();
        String mainClass = null;
        if(manifest != null) {
            mainClass = manifest.getMainAttributes().getValue("Start-Class");
        }

        if(mainClass == null) {
            throw new IllegalStateException("No \'Start-Class\' manifest entry specified in " + this);
        } else {
            return mainClass;
        }
    }

    protected List<Archive> getClassPathArchives() throws Exception {
        ArrayList archives = new ArrayList(this.archive.getNestedArchives(new EntryFilter() {
            public boolean matches(Entry entry) {
                return ExecutableArchiveLauncher.this.isNestedArchive(entry);
            }
        }));
        this.postProcessClassPathArchives(archives);
        return archives;
    }

    protected abstract boolean isNestedArchive(Entry var1);

    protected void postProcessClassPathArchives(List<Archive> archives) throws Exception {
    }
}

而 ExecutableArchiveLauncher 类又继承了 Launcher,而 Launcher 类中会实例化一个 MainMethodRunner 类,所以,我们项目中定义的 main 函数最张是由 MainMethodRunner 类来执行的,代码如下,通过反射的方式调用 main 函数。

package org.springframework.boot.loader;

import java.lang.reflect.Method;

public class MainMethodRunner {
    private final String mainClassName;
    private final String[] args;

    public MainMethodRunner(String mainClass, String[] args) {
        this.mainClassName = mainClass;
        this.args = args == null?null:(String[])args.clone();
    }

    public void run() throws Exception {
        Class mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
        Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
        mainMethod.invoke((Object)null, new Object[]{this.args});
    }
}




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot项目的真实程序入口 的相关文章

随机推荐

  • 基于预测控制模型的自适应巡航控制仿真与机器人实现(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 自适应巡航控制技术为目前由于汽车保有量不断增长而带来的行车安全 驾驶舒适性及交通拥堵等问题提供了一条有效的解决途径 因此本文通过理论分析 仿真验证及实车实验对自适应
  • 使用editor.md渲染markdown并自定义目录

    使用editor md渲染markdown并自定义目录 一 需求 最近在开发个人博客 在做文章详情页的时候 需要将markdown格式的文本字符串渲染成html页面 于是逛github的时候发现了这一款markdown在线编辑器 它支持将m
  • Json“牵手”亚马逊商品详情数据方法,亚马逊商品详情API接口,亚马逊API申请指南

    亚马逊平台是美国最大的一家网络电子商务公司 亚马逊公司是1995年成立 刚开始只做网上书籍售卖业务 后来扩展到了其他产品 现在已经是全世界商品品种最多的网上零售商和第二互联网公司 亚马逊是北美洲 欧洲等地区的主流购物平台 亚马逊商品分类接口
  • Office Visio 2007安装教程

    哈喽 大家好 今天一起学习的是Visio 2007的安装 这是一个绘制流程图的软件 用有效的绘图表达信息 比任何文字都更加形象和直观 Office Visio 是office软件系列中负责绘制流程图和示意图的软件 便于IT和商务人员就复杂信
  • SpringCloud与Dubbo的比较

    目录 Dubbo 一 dubbo简介 二 dubbo组织架构图 三 dubbo的优势 SpringCloud 一 SpringCloud简介 二 SpringCloud组织架构 三 SpringCloud特点 四 Dubbo与SpringC
  • 共模电感(扼流圈)选型

    1 共模电感原理 在介绍共模电感之前先介绍扼流圈 扼流圈是一种用来减弱电路里面高频电流的低阻抗线圈 为了提高其电感扼流圈通常有一软磁材料制的核心 共模扼流圈有多个同样的线圈 电流在这些线圈里反向流 因此在扼流圈的芯里磁场抵消 共模扼流圈常被
  • Python:打包生成.pyc、.pyd文件

    目录 pyd文件是什么 1 环境 2 待编译文件hello py以及setup py文件 3 运行调试 4 写在最后 pyd文件是什么 pyd文件类似于DLL 一般用C C 语言编译而成 可用作模块导入Python程序中 pyd文件仅适用于
  • 使用Unity游戏引擎在IOS模拟器中运行的方法

    在Unity编译IOS程序时 在Unity导航栏菜单中选择Edit gt ProjectSettings gt Player 菜单项 选择IOS平台在下方SDK Version处选择运行设备为IOS模拟器 选择完毕后Build and Ru
  • 任意代码执行漏洞简介

    一 任意代码执行漏洞思维导图 代码执行漏洞的成因 应用程序在调用一些能够将字符串转换为代码的函数 例如php中的eval中 没有考虑用户是否控制这个字符串 将造成代码执行漏洞 代码执行漏洞的常用函数 PHP eval assert preg
  • springcloud整合Hystrix

    作用 1 服务降级 触发情况 程序运行异常 超时 服务熔断触发服务降级 线程池 信号量打满也会触发服务降级 2 服务熔断 直接拒绝访问 即使有正确的访问也会短路 3 服务限流 排队有序进行 构建服务 1 建module provider h
  • 希沃白板5使用方法

    一 获取白板 手机和电脑都下载希沃白板五5 二 使用白板制作课件 1 获取课件 制作课件 方法一 1 点击课件库 2 点击右上角齿轮完成教材选择 3 找到所需课件 4 点击右下角箭头翻看 觉得可以点击 限免获取 5 点击云课件 找到刚才获取
  • .Net Core Json序列化和反序列化以及自定义JsonConverter来转化特殊日期时间格式

    System Text Json 命名空间提供用于序列化和反序列化 JavaScript 对象表示法 JSON 的功能 System Text Json 命名空间包含所有入口点和主要类型 System Text Json Serializa
  • ELK日志分析系统--Elasticserach安装

    ElK安装 安装es Elasticserach介绍 Elasticsearch是个开源分布式搜索引擎 提供搜集 分析 存储数据3大功能 特点有 分布式 零配置 自动发现 索引自动分片 索引副本机制 restful风格接口 多数据源 自动搜
  • 【Linux操作系统】【综合实验五 网络管理与通信】【更新中】

    文章目录 一 实验目的 二 实验要求 三 实验内容 四 实验报告要求 一 实验目的 要求了解和熟悉Linux网络客户 服务器管理模式 client server 与网络环境的配置 熟悉网络远程登录模式与TCP IP常见终端命令的使用 学会使
  • jmeter常见问题

    问题1 javax swing text BadLocationException Position not represented by view 解决方法 问题2 Could not instantiate class kg apc j
  • react项目中使用react-dnd实现列表的拖拽排序

    现在有一个新需求就是需要对一个列表 实现拖拽排序的功能 要实现的效果如下图 可以通过 react dnd 或者 react beautiful dnd 两种方式实现 今天先讲下使用react dnd是如何实现的 github地址 https
  • 1011 A+B 和 C

    给定区间 231 231 内的 3 个整数 A B 和 C 请判断 A B 是否大于 C 输入格式 输入第 1 行给出正整数 T 10 是测试用例的个数 随后给出 T 组测试用例 每组占一行 顺序给出 A B 和 C 整数间以空格分隔 输出
  • linux下更改文件的权限

    更改所属组 chgrp 语法 chgrp 组名 文件名 root localhost groupadd testgroup root localhost touch test1 root localhost ls l test1 rw r
  • SQL巧用表的自连接和运算符代替排序的几个例子

    MySQL巧用表的自连接和运算符代替排序的几个例子 目录 MySQL巧用表的自连接和运算符代替排序的几个例子 例1 SQL18 例2 SQL23 例3 SQL87 例1 SQL18 获取当前薪水第二多的员工的emp no以及其对应的薪水sa
  • Spring Boot项目的真实程序入口

    基于 spring boot start开发的项目 其程序入口并不是我们开发的业务代码中定义了 main 函数的类 而是 Spring Boot 定义的 JarLauncher 类 下文源码反编译自 spring boot loader 1