我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringBoot工程打包后执行Java -Jar就能启动的步骤原理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringBoot工程打包后执行Java -Jar就能启动的步骤原理

本文主要分享SpringBoot工程项目如何打包成一个可直接通过java -jar执行的jar,并且简单分析其启动步骤原理。

1.SpringBoot如何打包成一个可执行jar?

SpringBoot打包成成一个可执行jar需要依赖一个maven打包插件spring-boot-maven-plugin,如下所示在pom文件结尾的build节点添加依赖,同时将class="lazy" data-src/main/javaclass="lazy" data-src/main/resources打入jar里面。

 	<build>
        <resources>
            <resource>
                <directory>class="lazy" data-src/main/java</directory>
                <includes>
                    <include>***.*</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

此时再执行maven package打包成jar(最后打包完成在target目录下):

此时我们直接通过cmd控制台执行命令:java -jar boot-first-1.0.0-SNAPSHOT.jar 可以看到启动成功。

相关日志已经打印出来了,此时我们再通过postman验证一下编码中的接口是否生效:

程序中的接口代码如下:

2.SpringBoot打包成的jar为何可以直接Java -jar执行?

java程序的入口是main方法 ,如果一个jar能够通过java -jar执行起来,肯定离不开main方法。那springboot通过spring-boot-maven-plugin插件打包成的jar通常称为fat jar,里面不仅仅包含了程序代码还包括其他引用的依赖的jar。那这个fat jar的main方法入口在哪儿呢?我们通过解压该jar可以看到,在META-INF下的有一个MANIFEST.MF文件:

其中MANIFEST.MF中内容如下,其中比较重要的几行信息:

Start-Class: com.xren.bootfirst.BootFirstApplication ##程序开始类
Spring-Boot-Classes: BOOT-INF/classes/        ##加载的class
Spring-Boot-Lib: BOOT-INF/lib/   ##加载的内部jar位置
Main-Class: org.springframework.boot.loader.JarLauncher  ## boot启动类

综上可知,SpringBoot项目通过引入打包插件spring-boot-maven-plugin生成特定的主清单文件MANIFEST.MF,其中包含了程序的入口类和相关启动依赖。

3.一窥SpringBoot初启动

通用的jar包如果能被java -jar执行,只需要其MANIFEST.MF文件中有 Main-Class配置项即可。而此处SpringBoot的jar中的MANIFEST.MF文件里面不仅仅包含Main-Class 还有Start-Class、Spring-Boot-Classes、Spring-Boot-Lib等相关信息,那他们是如何运行的呢?我们还是要回到该jar主类org.springframework.boot.loader.JarLauncher来一窥究竟。

查看org.springframework.boot.loader.JarLauncher类需要pom引入spring-boot-loader,如下:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-loader</artifactId>
            <version>2.2.7.RELEASE</version>
	</dependency>

引入后其中JarLaunche类代码如下,它包含一个main方法,并且继承一个父类ExecutableArchiveLauncher。

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);
    }
}

从main方法进入我们需要关注一个launch方法,其中的三行

  • 注册一个jar处理类
  • 获取一个类加载器(通过路径加载lib和classs)
  • 通过获取主启动类和类加载器运行启动。
 protected void launch(String[] args) throws Exception {
        JarFile.registerUrlProtocolHandler();
        ClassLoader classLoader = this.createClassLoader(this.getClassPathArchives());
        this.launch(args, this.getMainClass(), classLoader);
    }

追寻this.getMainClass() 方法,其会指向上述的父类ExecutableArchiveLauncher中,此处就回到了我们开始说的Start-Class配置项。

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;
        }
    }

getMainClass()方法中的this.archive.getManifest() 就是获取jar下的META-INF/MANIFEST.MF文件。此处追寻到Archive的子类ExplodedArchive中,如下代码获取清单文件:

 	private File getManifestFile(File root) {
        File metaInf = new File(root, "META-INF");
        return new File(metaInf, "MANIFEST.MF");
    }

到此时清单文件中的Start-Class、Spring-Boot-Classes、Spring-Boot-Lib都已找到,准备启动!
回到org.springframework.boot.loader.Launcher的launch方法。

  • 当前线程设置类加载器
  • 创建主方法并运行(主方法即为Start-Class指向的类)
protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
        Thread.currentThread().setContextClassLoader(classLoader);
        this.createMainMethodRunner(mainClass, args, classLoader).run();
    }

以上两行代码具体实现在org.springframework.boot.loader.MainMethodRunner类中,run方法即为最后的启动逻辑

  • 通过当前线程类加载器载入清单文件Start-Class配置的主类。
  • 加载后获取主类中的main方法(XXXApplication中的main方法)。
  • 反射执行该XXXApplication中的main方法。
public MainMethodRunner(String mainClass, String[] args) {
        this.mainClassName = mainClass;
        this.args = args != null ? (String[])args.clone() : null;
    }
    public void run() throws Exception {
        Class<?> mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
        Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
        mainMethod.invoke((Object)null, this.args);
    }

至此,从执行java -jar命令,SpringBoot打包的jar启动到程序中XXXApplication中的main方法这一阶段我们就初步分析完了!

总结:SpringBoot通过引入打包插件spring-boot-maven-plugin将其相关信息写入到java-jar的META-INF/MANIFEST.MF文件中,而后通过清单文件中的主入口Main-Class配置的org.springframework.boot.loader.JarLauncher类加载相关class、lib和应用程序主类Start-Class配置的XXXApplication类,再反射获取XXXApplication类中我们业务定义的main方法启动运行。

到此这篇关于SpringBoot工程打包后为何执行Java -Jar就能启动?的文章就介绍到这了,更多相关springboot打包执行ava -Jar启动内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringBoot工程打包后执行Java -Jar就能启动的步骤原理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot工程打包后执行Java -Jar就能启动的步骤原理

这篇文章主要介绍了SpringBoot工程打包后为何执行Java -Jar就能启动,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录