文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

Springboot中FatJar和Jar是什么

2023-07-05 01:53

关注

这篇文章主要介绍“Springboot中FatJar和Jar是什么”,在日常操作中,相信很多人在Springboot中FatJar和Jar是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Springboot中FatJar和Jar是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

导读

Spring Boot应用可以使用spring-boot-maven-plugin快速打包,构建一个可执行jar。Spring Boot内嵌容器,通过java -jar命令便可以直接启动应用。

虽然是一个简单的启动命令,背后却藏着很多知识。今天带着大家探索FAT JAR启动的背后原理。本文主要包含以下几个部分:

JAR 是什么

JAR简介

JAR文件(Java归档,英语: Java ARchive)是一种软件包文件格式,通常用于将大量的Java类文件、相关的元数据和资源(文本、图片等)文件聚合到一个文件,以便分发Java平台应用软件或库。简单点理解其实就是一个压缩包,既然是压缩包那么为了提取JAR文件的内容,可以使用任何标准的unzip解压缩软件提取内容。或者使用Java虚拟机自带命令jar -xf foo.jar来解压相应的jar文件。

JAR 可以简单分为两类:

JAR结构

包结构

不管是非可行JAR还是可执行JAR解压后都包含两部分:META-INF目录(元数据)和package目录(编译后的class)。这种普通的jar不包含第三方依赖包,只包含应用自身的配置文件、class 等。

.├── META-INF│   ├── MANIFEST.MF  #定义└── org  # 包路径(存放编译后的class)    └── springframework
描述文件MANIFEST.MF

JAR包的配置文件是META-INF文件夹下的MANIFEST.MF文件。主要配置信息如下:

上面是普通jar包的属性,可运行jar包的.MF文件中,还会有mian-classstart-class等属性。如果依赖了外部jar包,还会在MF文件中配置lib路径等信息。更多信息参见:maven为MANIFEST.MF文件添加内容的方法

至于可运行jar包普通jar包的目录结构,没有什么特别固定的模式,总之,无论是什么结构,在.MF文件中,配置好jar包的信息,即可正常使用jar包了。

FatJar有什么不同

什么是FatJar?

普通的jar只包含当前 jar的信息,不含有第三方 jar。当内部依赖第三方jar时,直接运行则会报错,这时候需要将第三方jar内嵌到可执行jar里。将一个jar及其依赖的三方jar全部打到一个包中,这个包即为 FatJar。

SpringBoot FatJar解决方案

Spring Boot为了解决内嵌jar问题,提供了一套FatJar解决方案,分别定义了jar目录结构MANIFEST.MF。在编译生成可执行 jar 的基础上,使用spring-boot-maven-plugin按Spring Boot 的可执行包标准repackage,得到可执行的Spring Boot jar。根据可执行jar类型,分为两种:可执行Jar和可执行war。

spring-boot-maven-plugin打包过程

因为在新建的空的 SpringBoot 工程中并没有任何地方显示的引入或者编写相关的类。实际上,对于每个新建的 SpringBoot 工程,可以在其 pom.xml 文件中看到如下插件:

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

这个是SpringBoot官方提供的用于打包FatJar的插件,org.springframework.boot.loader下的类其实就是通过这个插件打进去的;

下面是此插件将 loader 相关类打入 FatJar 的一个执行流程:

org.springframework.boot.maven#execute->org.springframework.boot.maven#repackage -> org.springframework.boot.loader.tools.Repackager#repackage->org.springframework.boot.loader.tools.Repackager#writeLoaderClasses->org.springframework.boot.loader.tools.JarWriter#writeLoaderClasses

最终的执行方法就是下面这个方法,通过注释可以看出,该方法的作用就是将 spring-boot-loader 的classes 写入到 FatJar 中。

@Overridepublic void writeLoaderClasses() throws IOException {writeLoaderClasses(NESTED_LOADER_JAR);}
打包结果

Spring Boot项目被编译以后,在targert目录下存在两个jar文件:一个是xxx.jarxxx.jar.original

.├── BOOT-INF│   ├── classes│   │   ├── application.properties  # 用户-配置文件│   │   └── com│   │       └── glmapper│   │           └── bridge│   │               └── boot│   │                   └── BootStrap.class  # 用户-启动类│   └── lib│       ├── jakarta.annotation-api-1.3.5.jar│       ├── jul-to-slf4j-1.7.28.jar│       ├── log4j-xxx.jar # 表示 log4j 相关的依赖简写├── META-INF│   ├── MANIFEST.MF│   └── maven│       └── com.glmapper.bridge.boot│           └── guides-for-jarlaunch│               ├── pom.properties│               └── pom.xml└── org    └── springframework        └── boot            └── loader                ├── ExecutableArchiveLauncher.class                ├── JarLauncher.class                ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class                ├── LaunchedURLClassLoader.class                ├── Launcher.class                ├── MainMethodRunner.class                ├── PropertiesLauncher$1.class                ├── PropertiesLauncher$ArchiveEntryFilter.class                ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class                ├── PropertiesLauncher.class                ├── WarLauncher.class                ├── archive                │   ├── # 省略                ├── data                │   ├── # 省略                ├── jar                │   ├── # 省略                └── util                    └── SystemPropertyUtils.class

Spring Boot的MANIFEST.MF和普通jar有些不同:

Spring-Boot-Version: 2.1.3.RELEASEMain-Class: org.springframework.boot.loader.JarLauncherStart-Class: com.rock.springbootlearn.SpringbootLearnApplicationSpring-Boot-Classes: BOOT-INF/classes/Spring-Boot-Lib: BOOT-INF/lib/Build-Jdk: 1.8.0_131

Main-Class:java -jar启动引导类,但这里不是项目中的类,而是Spring Boot内部的JarLauncher
Start-Class: 这个才是正在要执行的应用内部主类

所以java -jar启动的时候,加载运行的是JarLauncher。Spring Boot内部如何通过JarLauncher 加载Start-Class 执行呢?为了更清楚加载流程,我们先介绍下java -jar是如何完成类加载逻辑的。

启动时的类加载原理

这里简单说下java -jar启动时是如何完成记载类加载的。Java 采用了双亲委派机制,Java语言系统自带有三个类加载器:

默认情况下通过java -classpathjava -cpjava -jar使用的类加载器都是AppClassLoader。 普通可执行jar通过java -jar启动后,使用AppClassLoader加载Main-class类。 如果第三方jar不在AppClassLoader里,会导致启动时候会报ClassNotFoundException。

例如在Spring Boot可执行jar的解压目录下,执行应用的主函数,就直接报该错误:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
        at com.glmapper.bridge.boot.BootStrap.main(BootStrap.java:13)
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 1 more

从异常堆栈来看,是因为找不到SpringApplication这个类;这里其实还是比较好理解的,BootStrap类中引入了SpringApplication,但是这个类是在BOOT-INF/lib下的,而java指令在启动时未指明classpath,依赖的第三方jar无法被加载。

Spring Boot JarLauncher启动时,会将所有依赖的内嵌 jar (BOOT-INF/lib 目录下) 和class(BOOT-INF/classes 目录)都加入到自定义的类加载器LaunchedURLClassLoader中,并用这个ClassLoder去加载MANIFEST.MF配置Start-Class,则不会出现类找不到的错误。

LaunchedURLClassLoader是URLClassLoader的子类, URLClassLoader会通过URL[] 来搜索类所在的位置。Spring Boot 则将所需要的内嵌文档组装成URL[],最终构建LaunchedURLClassLoader类。

启动的整个流程

有了以上知识的铺垫,我们看下整个 FatJar 启动的过程会是怎样。为了以便查看源码和远程调试,可以在 pom.xml 引入下面的配置:

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

简单概括起来可以分为几步:

到此,关于“Springboot中FatJar和Jar是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

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

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

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯