前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Spring Boot2 系列教程(四十)Spring Boot 可执行 jar 分析

Spring Boot2 系列教程(四十)Spring Boot 可执行 jar 分析

作者头像
江南一点雨
发布于 2019-12-18 07:42:05
发布于 2019-12-18 07:42:05
1.5K00
代码可运行
举报
文章被收录于专栏:玩转JavaEE玩转JavaEE
运行总次数:0
代码可运行

前两天被人问到这样一个问题:

“松哥,为什么我的 Spring Boot 项目打包成的 jar ,被其他项目依赖之后,总是报找不到类的错误?”

大伙有这样的疑问,就是因为还没搞清楚可执行 jar 和普通 jar 到底有什么区别?今天松哥就和大家来聊一聊这个问题。

多了一个插件

Spring Boot 中默认打包成的 jar 叫做 可执行 jar,这种 jar 不同于普通的 jar,普通的 jar 不可以通过 java -jar xxx.jar 命令执行,普通的 jar 主要是被其他应用依赖,Spring Boot 打成的 jar 可以执行,但是不可以被其他的应用所依赖,即使强制依赖,也无法获取里边的类。但是可执行 jar 并不是 Spring Boot 独有的,Java 工程本身就可以打包成可执行 jar 。

有的小伙伴可能就有疑问了,既然同样是执行 mvn package 命令进行项目打包,为什么 Spring Boot 项目就打成了可执行 jar ,而普通项目则打包成了不可执行 jar 呢?

这我们就不得不提 Spring Boot 项目中一个默认的插件配置 spring-boot-maven-plugin ,这个打包插件存在 5 个方面的功能,从插件命令就可以看出:

五个功能分别是:

  • build-info:生成项目的构建信息文件 build-info.properties
  • repackage:这个是默认 goal,在 mvn package 执行之后,这个命令再次打包生成可执行的 jar,同时将 mvn package 生成的 jar 重命名为 *.origin
  • run:这个可以用来运行 Spring Boot 应用
  • start:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理
  • stop:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理

这里功能,默认情况下使用就是 repackage 功能,其他功能要使用,则需要开发者显式配置。

打包

repackage 功能的 作用,就是在打包的时候,多做一点额外的事情:

  1. 首先 mvn package 命令 对项目进行打包,打成一个 jar,这个 jar 就是一个普通的 jar,可以被其他项目依赖,但是不可以被执行
  2. repackage 命令,对第一步 打包成的 jar 进行再次打包,将之打成一个 可执行 jar ,通过将第一步打成的 jar 重命名为 *.original 文件

举个例子:

对任意一个 Spring Boot 项目进行打包,可以执行 mvn package 命令,也可以直接在 IDEA 中点击 package ,如下 :

打包成功之后, target 中的文件如下:

这里有两个文件,第一个 restful-0.0.1-SNAPSHOT.jar 表示打包成的可执行 jar ,第二个 restful-0.0.1-SNAPSHOT.jar.original 则是在打包过程中 ,被重命名的 jar,这是一个不可执行 jar,但是可以被其他项目依赖的 jar。通过对这两个文件的解压,我们可以看出这两者之间的差异。

两种 jar 的比较

可执行 jar 解压之后,目录如下:

可以看到,可执行 jar 中,我们自己的代码是存在 于 BOOT-INF/classes/ 目录下,另外,还有一个 META-INF 的目录,该目录下有一个 MANIFEST.MF 文件,打开该文件,内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Manifest-Version: 1.0
Implementation-Title: restful
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: org.javaboy.restful.RestfulApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.6.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher

可以看到,这里定义了一个 Start-Class,这就是可执行 jar 的入口类,Spring-Boot-Classes 表示我们自己代码编译后的位置,Spring-Boot-Lib 则表示项目依赖的 jar 的位置。

换句话说,如果自己要打一个可执行 jar 包的话,除了添加相关依赖之外,还需要配置 META-INF/MANIFEST.MF 文件。

这是可执行 jar 的结构,那么不可执行 jar 的结构呢?

我们首先将默认的后缀 .original 除去,然后给文件重命名,重命名完成,进行解压:

解压后可以看到,不可执行 jar 根目录就相当于我们的 classpath,解压之后,直接就能看到我们的代码,它也有 META-INF/MANIFEST.MF 文件,但是文件中没有定义启动类等。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Manifest-Version: 1.0
Implementation-Title: restful
Implementation-Version: 0.0.1-SNAPSHOT
Build-Jdk-Spec: 1.8
Created-By: Maven Archiver 3.4.0

注意

这个不可以执行 jar 也没有将项目的依赖打包进来。

从这里我们就可以看出,两个 jar ,虽然都是 jar 包,但是内部结构是完全不同的,因此一个可以直接执行,另一个则可以被其他项目依赖。

一次打包两个 jar

一般来说,Spring Boot 直接打包成可执行 jar 就可以了,不建议将 Spring Boot 作为普通的 jar 被其他的项目所依赖。如果有这种需求,建议将被依赖的部分,单独抽出来做一个普通的 Maven 项目,然后在 Spring Boot 中引用这个 Maven 项目。

如果非要将 Spring Boot 打包成一个普通 jar 被其他项目依赖,技术上来说,也是可以的,给 spring-boot-maven-plugin 插件添加如下配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <classifier>exec</classifier>
            </configuration>
        </plugin>
    </plugins>
</build>

配置的 classifier 表示可执行 jar 的名字,配置了这个之后,在插件执行 repackage 命令时,就不会给 mvn package 所打成的 jar 重命名了,所以,打包后的 jar 如下:

第一个 jar 表示可以被其他项目依赖的 jar ,第二个 jar 则表示一个可执行 jar。

好了,关于 Spring Boot 中 jar 的问题,我们就说这么多,有问题欢迎留言讨论。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江南一点雨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Spring Boot 主类及目录结构介绍
Spring Boot 与传统项目最大的区别是,传统项目都是打成 WAR 包部署到服务器上面,需要额外的 Servlet 容器, 而 Spring Boot 则可以直接打成 jar 包,并内置集成了 Servlet 容器,通过命令 java -jar xx.jar 则可以直接运行,不需要独立的 Servlet 容器。
Java技术栈
2018/09/29
1.3K0
springboot的jar为何能独立运行
在开发springboot应用时,通过java -jar命令启动应用是常用的方式,今天就来一起了解这个简单操作背后的技术;
程序员欣宸
2021/05/13
7700
springboot的jar为何能独立运行
Spring Boot 项目打包问题集锦: jar依赖多出boot-inf 文件夹问题/多环境动态打包/缺少BOOT-INF目录问题等
使用maven插件打包后,发现包很小100来kb,显然是不对,包内缺少BOOT-INF目录,BOOT-INF是用于存放引用的外部lib的,所以缺少,打出来的包根本不能运行:
一个会写诗的程序员
2021/07/15
3.4K0
SpringBoot 创建可执行Jar
  我们也可以通过插件创建一个在生产环境中运行的可执行jar文件来完成我们的示例。
2019/02/21
1K0
SpringBoot 创建可执行Jar
Spring Boot 打包成的可执行 jar ,为什么不能被其他项目依赖?
“松哥,为什么我的 Spring Boot 项目打包成的 jar ,被其他项目依赖之后,总是报找不到类的错误?”
江南一点雨
2019/07/10
2.9K0
SpringBoot打包部署解析:jar包的生成和结构
SpringBoot项目支持两种常见的打包形式: jar 包和 war 包。默认情况下创建的 Spring Boot项目是采用 jar 包形式,如果项目需要 war 包,可通过修改配置打成 war 包。
愿天堂没有BUG
2022/10/28
1.8K0
SpringBoot打包部署解析:jar包的生成和结构
Spring Boot 怎么打一个可执行 Jar 包?
传统的 Java 应用程序都需要打一个 war 包,并到到 Tomcat webapps 目录下运行。
Java技术栈
2019/10/29
1.4K0
企业都在用的 spring boot 打包插件,真的超好用!
在平时的项目中,我们用到了 spring boot 默认的插件 spring-boot-maven-plugin 来进行打包,打的包是直接可执行的。但是这次,有一个多模块项目,我负责其中一个模块的开发,开发完成之后,发现打的包直接执行报找不到主类,这就有点奇怪了,所以就有了这篇文章。
create17
2020/07/14
1.8K0
企业都在用的 spring boot 打包插件,真的超好用!
当我们的执行 java -jar xxx.jar 的时候底层到底做了什么?
大家都知道我们常用的 SpringBoot 项目最终在线上运行的时候都是通过启动 java -jar xxx.jar 命令来运行的。
Java极客技术
2023/02/23
7690
当我们的执行 java -jar xxx.jar 的时候底层到底做了什么?
Spring Boot Maven Plugin打包异常及三种解决方法:Unable to find main class
【背景】spring-boot项目,打包成可执行jar,项目内有两个带有main方法的类并且都使用了@SpringBootApplication注解(或者另一种情形:你有两个main方法并且所在类都没有使用@SpringBootApplication注解),pom.xml如下 <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <v
庞小明
2018/07/06
15.9K0
Spring boot 项目打出来的包启动过程
spring boot 的工程支持打包为jar和war,打包成 jar 或 war 可以直接用 java -jar xxx.jar 来启动,war包也可以放入tomcat等容器中运行。
前Thoughtworks-杨焱
2021/12/07
1.7K0
Spring boot 项目打出来的包启动过程
Spring Boot2 系列教程(四十一)部署 Spring Boot 到远程 Docker 容器
不知道各位小伙伴在生产环境都是怎么部署 Spring Boot 的,打成 jar 直接一键运行?打成 war 扔到 Tomcat 容器中运行?不过据松哥了解,容器化部署应该是目前的主流方案。
江南一点雨
2019/12/19
8870
Spring Boot2 系列教程(四十一)部署 Spring Boot 到远程 Docker 容器
SpringBoot - 探究Spring Boot应用是如何通过java -jar 启动的
大家开发的基于Spring Boot 的应用 ,jar形式, 发布的时候,绝大部分都是使用java -jar 启动。 得益于Spring Boot 的封装 , 再也不用操心搭建tomcat等相关web容器le , 一切变得非常美好, 那SpringBoot是怎么做到的呢?
小小工匠
2021/08/17
1.5K0
SpringBoot - 探究Spring Boot应用是如何通过java -jar 启动的
SpringBoot系列-- jar可执行原理
文章篇幅较长,但是包含了SpringBoot 可执行jar包从头到尾的原理,请读者耐心观看。
田维常
2020/02/13
9430
启动SpringBoot的可执行jar 报错:target\spring-boot-hello-1.0-SNAPSHOT.jar中没有主清单属性
   原因:查看了MANIFEST.MF,发现没有Main-Class属性,我想了一下,就试着去SpringBoot的官方文档上找找,果然有讲这一部分,spring-boot-maven-plugin的打包过程与直接使用maven-jar-plugin不同,所以我们在使用spring-boot-maven-plugin时需要指定的执行项,或者我们在打包时指定,使用 mvn package spring-boot:repackage来打包也可以执行。
2019/02/21
6.4K0
启动SpringBoot的可执行jar  报错:target\spring-boot-hello-1.0-SNAPSHOT.jar中没有主清单属性
spring boot 使用maven和fat jar/war运行应用程序的对比
上篇文章我们介绍了Spring boot的fat jar/war包,jar/war包都可以使用 java -jar 命令来运行,而maven也提供了mvn spring-boot:run 命令来运行应用程序,下面我们看看两者有什么不同。
程序那些事
2020/07/08
1.6K0
SpringBoot Jar包瘦身 - 跟大文件说再见!
SpringBoot部署起来配置非常少,如果服务器部署在公司内网,上传速度还行,但是如果部署在公网(阿里云等云服务器上),部署起来实在头疼、就是 编译出来的 Jar 包很大,如果工程引入了许多开源组件(SpringCloud等),那就更大了。这个时候如果想要对线上运行工程有一些微调,则非常痛苦
云扬四海
2019/08/06
1.8K0
Spring Boot 核心编程思想-第一部分-读书笔记「建议收藏」
本文是Spring Boot核心编程思想记录的笔记,书籍地址:Spring Boot编程思想(核心篇):
全栈程序员站长
2022/07/20
9620
Spring Boot 核心编程思想-第一部分-读书笔记「建议收藏」
你的SpringBoot应用真的部署更新成功了吗
当我们在生产环境部署了SpringBoot应用的时候,虽然可以通过Jenkins的构建状态和Linux的ps命令去感知应用是否在新的一次发布中部署和启动成功,但是这种监控手段是运维层面的。那么,可以提供一种手段能够在应用层面感知服务在新的一次发布中的构建部署和启动是否成功吗?这个问题笔者花了一点时间想通了这个问题,通过这篇文章提供一个简单的实现思路。
Throwable
2020/06/23
8590
Jar包部署为linux系统服务
启动服务: systemctl start nansha重启服务systemctl restart nansha查看该服务的状态:systemctl status nansha停止服务并从自启动项中删除
公众号iOS逆向
2024/06/27
3000
Jar包部署为linux系统服务
推荐阅读
相关推荐
Spring Boot 主类及目录结构介绍
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文