SpringBoot应用能直接运行java -jar的原因分析

 更新时间:2024年03月06日 09:45:36   作者:hbqst  
这篇文章主要介绍了SpringBoot应用为什么能直接运行java -jar,首先明确一点,普通jar包是不能直接运行的,比如工具类jar,要能运行,至少得要一个main函数作为入口吧?本文给大家介绍了详细的原因分析,需要的朋友可以参考下

首先明确一点,普通jar包是不能直接运行的,比如工具类jar

要能运行,至少得要一个main函数作为入口吧?

SpringBoot应用确实有个main函数,那么问题来了,java -jar是怎么找到这个main函数运行的?

先说答案

是因为引入了spring-boot-maven-plugin插件

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

不信?

现在不使用这个插件,将SpringBoot应用打个jar包

target目录产出文件如下

在这里插入图片描述

注意此时的jar体积为3202KB,内容只包含了项目中的代码和resources下的文件

在这里插入图片描述

尝试java -jar运行,报错没有主清单属性

在这里插入图片描述

这是把spring-boot-maven-plugin插件加上,再次打包

target目录如下

在这里插入图片描述

jar包体积变大了!另外多出一个jar.origin,大小和之前jar包的一样

当然我们只需要关系jar即可

查看jar包中的内容,不仅包含了自己写的类(classes),还将依赖的第三方jar包全部装了进来(lib),这种jar被称为fat jar

在这里插入图片描述

这时使用java -jar命令,成功运行!

在这里插入图片描述

按照常规思路,一定是要找到main方法所在的这个类,然后去运行里面的main方法

其实,当执行java -jar时,会自动去找一个叫MANIFEST.MF的文件,然后根据其中的Main-Class找到入口类,并执行其中的main方法

在这里插入图片描述

而SpringBoot的jar包的这个文件,就是spring-boot-maven-plugin这个插件生成的

这个文件中的内容如下

Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Archiver-Version: Plexus Archiver
Built-By: yimin
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Start-Class: com.example.k8sdemo.K8sDemoApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.6.13
Created-By: Apache Maven 3.8.8
Build-Jdk: 1.8.0_392
Main-Class: org.springframework.boot.loader.JarLauncher

好家伙,Main-Class居然不是我们自己写的那个类

而是org.springframework.boot.loader.JarLauncher

想要查看这个类,先引入以下依赖

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

JarLauncher的main函数以及方法调用如下

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

protected void launch(String[] args) throws Exception {
	if (!isExploded()) {
		JarFile.registerUrlProtocolHandler();
	}
	ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator());
	String jarMode = System.getProperty("jarmode");
	String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass();
	launch(args, launchClass, classLoader);
}


@Override
protected String getMainClass() throws Exception {
	String mainClass = getProperty(MAIN, "Start-Class");
	if (mainClass == null) {
		throw new IllegalStateException("No '" + MAIN + "' or 'Start-Class' specified");
	}
	return mainClass;
}


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


protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
	return new MainMethodRunner(mainClass, args);
}

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

总结一下就是

  • 创建一个自定义的类加载器LaunchedURLClassLoader
  • 使用这个自定义的ClassLoader去加载我们自己写的main方法类,这个类由MANIFEST.MF中Start-Class定义
  • 反射获取main方法,然后执行

以上就是SpringBoot应用能直接运行java -jar的原因分析的详细内容,更多关于SpringBoot直接运行java -jar的资料请关注脚本之家其它相关文章!

相关文章

  • Java精确抽取网页发布时间

    Java精确抽取网页发布时间

    这篇文章主要为大家详细介绍了Java精确抽取网页发布时间的相关资料,尽量做到精确无误,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Java如何使用Iterator迭代器删除集合重复选项

    Java如何使用Iterator迭代器删除集合重复选项

    这篇文章主要介绍了Java如何使用Iterator迭代器删除集合重复选项,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Java Long转JSON出现精度丢失问题及解决

    Java Long转JSON出现精度丢失问题及解决

    Java Long类型转JSON时可能因JSON的通用数字类型不指定位数大小及JavaScript整数表达精度限制导致精度丢失,解决方法包括在Java对象中为Long类型字段添加@JsonFormat(shape=JsonFormat.Shape.STRING)注解,或在Spring框架中配置ObjectMapper以全局序列化行为
    2025-12-12
  • Java实现简单的分页功能

    Java实现简单的分页功能

    这篇文章主要为大家详细介绍了Java实现简单的分页功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • Jmeter多台机器并发请求实现压力性能测试

    Jmeter多台机器并发请求实现压力性能测试

    这篇文章主要介绍了Jmeter多台机器并发请求实现压力性能测试,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • spring异步service中处理线程数限制详解

    spring异步service中处理线程数限制详解

    这篇文章主要给大家介绍了关于spring异步service中处理线程数限制的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • RabbitMq 常用命令和REST API详解

    RabbitMq 常用命令和REST API详解

    RabbitMQ管理命令涵盖服务启停、用户权限、虚拟主机、队列操作、消息管理及集群配置,包含创建/删除用户、设置角色、绑定交换机与队列、REST API数据查询等关键操作,需注意参数格式和角色唯一性限制,本文给大家介绍RabbitMq常用命令和REST API,感兴趣的朋友一起看看吧
    2025-07-07
  • SpringBoot DFA实现敏感词过滤功能

    SpringBoot DFA实现敏感词过滤功能

    传统的字符串查找方式在处理大量敏感词时性能急剧下降,而正则表达式在匹配复杂规则时更是捉襟见肘,今天,介绍一种基于 DFA(有限状态自动机)算法的高效敏感词过滤方案,感兴趣的可以了解下
    2025-11-11
  • 浅析JVM的垃圾回收器

    浅析JVM的垃圾回收器

    这篇文章主要介绍了JVM垃圾回收器的相关资料,帮助大家更好的理解和学习Java虚拟机的相关知识,感兴趣的朋友可以了解下
    2020-11-11
  • Java多线程之synchronized同步代码块详解

    Java多线程之synchronized同步代码块详解

    这篇文章主要为大家详细介绍了Java多线程之synchronized同步代码块,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03

最新评论