返回顶部
首页 > 资讯 > 精选 >Springboot中FatJar和Jar是什么
  • 692
分享到

Springboot中FatJar和Jar是什么

2023-07-05 01:07:17 692人浏览 独家记忆
摘要

这篇文章主要介绍“SpringBoot中Fatjar和Jar是什么”,在日常操作中,相信很多人在springboot中FatJar和Jar是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Springboo

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

    导读

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

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

    • JAR 是什么。首先需要了解jar是什么,才知道java -jar做了什么事情。

    • FatJar 有什么不同。 Spring Boot提供的可执行jar与普通的jar有什么区别。

    • 启动时的类加载原理。 启动过程中类加载器做了什么?Spring Boot又如何通过自定义类加载器解决内嵌包的加载问题。

    • 启动的整个流程。最后整合前面三部分的内容,解析源码看如何完成启动。

    JAR 是什么

    JAR简介

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

    JAR 可以简单分为两类:

    • 非可执行JAR。打包时,不用指定main-class,也不可运行。普通jar包可以供其它项目进行依赖。

    • 可执行JAR。打jar包时,指定了main-class类,可以通过java -jar xxx.jar命令,执行main-classmain方法,运行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文件。主要配置信息如下:

    • Manifest-Version: 用来定义manifest文件的版本,例如:Manifest-Version: 1.0

    • Created-By: 声明该文件的生成者,一般该属性是由jar命令行工具生成的,例如:Created-By: Apache Ant 1.5.1

    • Signature-Version: 定义jar文件的签名版本

    • Class-Path: 应用程序或者类装载器使用该值来构建内部的类搜索路径,可执行jar包里需要设置这个。

    上面是普通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

    • 其中xxx.jar.original是maven编译后的原始jar文件,即标准的java jar。该文件仅包含应用本地资源。 如果单纯使用这个jar,无法正常运行,因为缺少依赖的第三方资源。

    • 因此spring-boot-maven-plugin插件对这个xxx.jar.original再做一层加工,引入第三方依赖的jar包等资源,将其 "repackage"xxx.jar。可执行Jar的文件结构如下图所示:

    .├── 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
    • META-INF: 存放元数据。MANIFEST.MF 是 jar 规范,Spring Boot 为了便于加载第三方 jar 对内容做了修改;

    • org: 存放Spring Boot 相关类,比如启动时所需的 Launcher 等;

    • BOOT-INF/class: 存放应用编译后的 class 文件;

    • BOOT-INF/lib: 存放应用依赖的 JAR 包。

    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语言系统自带有三个类加载器:

    • Bootstrap CLassloder: 最顶层的加载类,主要加载核心类库

    • Extention ClassLoader: 扩展的类加载器,加载目录%JRE_HOME%/lib/ext目录下的jar包和class文件。 还可以加载-D java.ext.dirs选项指定的目录。

    • AppClassLoader: 是应用加载器。

    默认情况下通过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>

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

    • java -jar 启动,AppClassLoader 则会加载 MANIFEST.MF 配置的Main-Class, JarLauncher。

    • JarLauncher启动时,注册URL关联协议。

    • 获取所有内嵌的存档(内嵌jar和class)

    • 根据存档的URL[]构建类加载器。

    • 然后用这个类加载器加载Start-Class。 保证这些类都在同一个ClassLoader中。

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

    --结束END--

    本文标题: Springboot中FatJar和Jar是什么

    本文链接: https://lsjlt.com/news/349014.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Springboot中FatJar和Jar是什么
      这篇文章主要介绍“Springboot中FatJar和Jar是什么”,在日常操作中,相信很多人在Springboot中FatJar和Jar是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Springboo...
      99+
      2023-07-05
    • java中的jar文件是什么
      java中的jar文件介绍:(推荐:java视频教程)JAR 文件就是 Java Archive File,顾名思意,它的应用是与 Java 息息相关的,是 Java 的一种文档格式。JAR 文件非常类似 ZIP 文件——准确的说,它就是 ...
      99+
      2018-11-25
      java
    • mysql的jar包是什么
      MySQL的JAR包是指用于Java编程语言连接和操作MySQL数据库的相关库文件,包含了一些用于实现与MySQL数据库通信和交互所需的类和方法,具有以下功能和特性:1、提供了与MySQL数据库建立连接、断开连接和管理连接池等功能;2、支持...
      99+
      2023-07-28
    • springboot中@Controller和@RestController的区别是什么
      小编给大家分享一下springboot中@Controller和@RestController的区别是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!@Cont...
      99+
      2023-06-25
    • web.xml SpringBoot打包可执行Jar运行SpringMVC的方法是什么
      这篇文章主要讲解了“web.xml SpringBoot打包可执行Jar运行SpringMVC的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“web.xml S...
      99+
      2023-07-05
    • SpringBoot为什么可以使用Jar包启动
      这篇文章将为大家详细讲解有关SpringBoot为什么可以使用Jar包启动,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。引言很多初学者会比较困惑,Spring Boot 是如何做到将应用代码和所有的依赖打...
      99+
      2023-06-29
    • Spring和SpringBoot的区别是什么
      今天小编给大家分享一下Spring和SpringBoot的区别是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、看一下...
      99+
      2023-06-27
    • springboot和mybatis的关系是什么
      Spring Boot和MyBatis的关系是,Spring Boot是一个用于简化Spring应用程序开发的框架,而MyBatis...
      99+
      2023-10-11
      springboot mybatis
    • j2ee和springboot的区别是什么
      J2EE(Java 2 Platform, Enterprise Edition)是一种大型的企业级Java开发平台,提供了一整套的...
      99+
      2024-04-02
    • SpringBoot application.yml和bootstrap.yml的区别是什么
      本篇内容介绍了“SpringBoot application.yml和bootstrap.yml的区别是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家...
      99+
      2023-07-06
    • springboot从application.properties中注入list和map方式是什么
      本篇内容主要讲解“springboot从application.properties中注入list和map方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot从appli...
      99+
      2023-06-21
    • SpringBoot中HttpSession的作用是什么
      在Spring Boot中,HttpSession是用于在Web应用程序中跟踪用户会话状态的机制。它是一个用于存储和获取与特定用户相...
      99+
      2023-09-26
      SpringBoot
    • springboot中starter的作用是什么
      在Spring Boot中,starter是一种用于简化依赖管理和配置的特殊类型的依赖项。它们是预先配置的一组依赖项,可以在项目中添...
      99+
      2023-10-26
      springboot
    • springboot中properties的用法是什么
      在Spring Boot中,properties文件是一种常用的配置文件格式,用来配置应用程序的各种属性。这些属性可以包括数据库连接...
      99+
      2024-04-02
    • springboot-starter-undertow和tomcat的区别是什么
      本篇内容主要讲解“springboot-starter-undertow和tomcat的区别是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot-starter-undert...
      99+
      2023-06-29
    • SpringBoot之bootstrap和application的区别是什么
      本篇内容主要讲解“SpringBoot之bootstrap和application的区别是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot之bootstrap和applic...
      99+
      2023-07-05
    • SpringBoot怎么删除引用jar包中的无用bean
      这篇文章主要讲解了“SpringBoot怎么删除引用jar包中的无用bean”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot怎么删除引用jar包中的无用bean”吧!前言公...
      99+
      2023-07-02
    • 怎么在SpringBoot项目中使用redis工具jar包
      本篇文章为大家展示了怎么在SpringBoot项目中使用redis工具jar包,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、Redis常用存储操作实现(redis-util模块,该module最...
      99+
      2023-06-08
    • android编译jar包的方法是什么
      Android编译jar包的方法如下:1. 首先,在Android Studio中打开项目。2. 在项目的根目录下创建一个新的mod...
      99+
      2023-09-23
      android
    • MySQL的Jar包是什么?详细解析
      MySQL的Jar包是指用于连接和操作MySQL数据库的Java驱动程序包。在Java开发中,需要通过Jar包来实现与MySQL数据库的交互功能。MySQL的Jar包提供了一系列的类和...
      99+
      2024-03-01
      mysql jar包 解析 sql语句
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作