首页 » Web前端 » phpinvalidlibrary技巧_SpringBoot打包支配解析jar包的生成和结构

phpinvalidlibrary技巧_SpringBoot打包支配解析jar包的生成和结构

访客 2024-12-01 0

扫一扫用手机浏览

文章目录 [+]

本章我们将环绕 jar 包和 war 包的运作事理及干系操作进行讲解。

SpringBoo的jar 包

Spring Boot 的 jar 包项目发布形式大略、快捷且内置 web 容器,因此 Spring Boot 将其作为默认选项。
在享受便利的同时,我们也须要多少理解一下 Spring Boot 的 jar 包是如何天生的,以及如何通过 jar 包启动运行。
本节从 jar 包的天生、构造、运作事理来剖析 Spring Boot的实现。

phpinvalidlibrary技巧_SpringBoot打包支配解析jar包的生成和结构

jar包的天生

Spring Boot 的可实行 jar 包又称作 fat jar”,是包含所有三方依赖的 jar。
它与传统 jar 包最大的不同是包含了一个 lib 目录和内嵌了 web 容器(以下均以 tomcat 为例)。

phpinvalidlibrary技巧_SpringBoot打包支配解析jar包的生成和结构
(图片来自网络侵删)

jar 包通 常是由集成在 pom.xml 文件中的 maven 插件来天生的。

配置在 pom 文件 build 元素中的 plugins 内。

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

spring-boot-maven-plugin 项目存在于 spring-boot-tools 目录中。
spring-boot-maven-plugin默认有 5 个 goals: repackage、 run、 start、 stop、 build-info。
在打包的时候默认利用的是 repackage。

spring-boot-maven-plugin 的 repackage 能够将 mvn package 天生的软件包,再次打包为可实行的软件包,并将 mvn package 天生的软件包重命名为.original。

这就为什么当实行 maven clean package 时,spring-boot-maven-plugin 会在 target 目录下天生两个 jar 文件。

spring - learn-0.0.1- SNAPSHOT. jar

spring - learn-0.0.1- SNAPSHOT . jar . original个中我们可以将 spring-learn-0.0. 1-SNAPSHOTjar.original 文件的后缀 original 去掉,天生的新jar包便是包含业务代码的包(普通的jar包) 。
其余的spring-learn-0.0. 1-SNAPSHOTjar包则是在 Spring Boot 中通过 jar jar 启动的包,它包含了运用的依赖,以及 spring boot 干系 class。

spring-boot-maven-plugin 的 repackage 在代码层面调用了 RepackageMojo 的 execute 方法。
RepackageMojo 类便是 供应重新打包现有的 jar 或 war 包文件,使得它们可以利用 javajar 来进行启动。

RepackageMojo 的 execute 方法如下。

@Overridepublic void execute() throws MojoExecut ionException, MojoFailureExceptionif (this. project . getPackaging() . equals("pom")) {getLog() . debug("repackage goal could not be applied to pom project.");return;if (this.skip) {getLog() . debug("skipping repackaging as per configuration.");return;repackage();}

在 execute 方法中止定了是否为 pom 项目和是否跳过,如果是,则打印 debug 日志并返回;否则连续实行 repackage 方法。
RepackageMojo 中的 repackage 方法干系源代码及操作解析如下。

private void repackage() throws MojoExecutionException {// maven 天生的 jar, 终极的命名将加上. original 后缀Artifact source = getSourceArtifact();//终极为可实行 jar,即 fat jarFile target = getTargetFile();//获取重新打包器,将 maven 生 成的 jar 重新打包成可实行 jarRepackager repackager = getRepackager(source . getFile());//查找并过滤项目运行时依赖的 jarSet<Artifact> artifacts = filterDependenc ies(this . project. getArtifacts(),getFilters(getAdditionalFilters()));//将 artifacts 转换成 L ibrariesLibraries libraries = new ArtifactsLibraries(artifacts, this . requiresUnpak,getLog());ry {/得到 Spring Boot 启动脚本LaunchScript launchScript = getLaunchScript();//实行重新打包,天生 fat jarrepackager . repackage(target, libraries, launchScript);catch (IOException ex) {throw new MojoExecut ionException(ex. getMessage(), ex); }将 maven 天生的 jar 更新成 original 文件updateArtifact(source, target, repackager . getBackupFile());}

关于全体 repackage 方法的操作流程在上面代码中已经进行相应注释解释,其基本过程为:得到 maven 天生的普通 jar 包、得到目标 File 工具、得到重新打包器、得到依赖 jar 包、 得到启动脚本,末了通过重新打包器进行重新打包为可通过 java -jar 实行的 jar 包。

个中我们重点看获取 Repackager 的方法 getRepackager 的源代码。

private Repackager getRepackager(File source) {Repackager repackager = new Repackager(source, this . layoutFactory);repackager . addMainClassTimeoutWarningL istener(new LoggingMainClassTimeoutWarningl istener());//设置 main class 的名称,如果不指定, 则会查找第一个包含 main 方法的类// repackage 末了将会设置 org. springframework . boot . Loader. JarLauncherrepackager . setMainClass(this . mainClass);if (this.layout != null) {getLog(). info("Layout: "+this. layout);//比如,layout 返@org. springframework. boot. loader. tools. Layouts . Jarrepackager . setLayout(this . layout. layout());}return repackager;}

getRepackager 方法紧张是根据将要被转换的文件(jar 或 war) 创建了 Repackager 工具,并设置启动用的 MainClass 为 org. springframework.boot.loader.JarLauncher,该配置对应于 jar 包中 Manifest.MF 文件内的 MainClass 值。

同时,如果 layout 不为 null, 通过内部列举类 L ayoutType 供应的 layout 方法获取对应的重新打包的实现类,比如针对 jar 包的 org.springframework. boot.loader.tools.Layouts.Jar 类。

列举类 LayoutType 的定义如下。

public enum LayoutType {JAR(new Jar()),WAR(new War()),ZIP(new Expanded()),DIR(new Expanded()),NONE(new None());}

从 LayoutType 的定义可以看出,Spring Boot 实在是支持多种类型的 archive ( 即归档文件) : jar 类型、war 类型、zip 类型、 文件目录类型和 NONE。
很显然,利用了相同的实现类来处理 ZIP 文件和 DIR 文件。

jar 类型为 Layouts 类的内部类,可以大略看一下 jar 类型的处理类都包含 了哪些内容。

public static class Jar implements RepackagingLayout {//获取详细的 L ancher 类全路径@Overridepublic String getLauncherClassName() {return "org. springframework. boot . loader.Jarlauncher";/得到详细的依赖 jar 包路径@Overridepublic String getL ibraryDestination(String libraryName, LibraryScope scopreturn "BOOT - INF/lib/";//获取重新打包的 class 文件路径@Overridepublic String getRepackagedClassesLocation() {return "BOOT -INF/classes/";}}

通过源代码可以看出,jar 类型的归档文件(jar 包) 中包含了 jar 包启动的 Main-class ( JarLauncher )BOOT-INF/lib/目录和 BOOT-INF/classes/目录。
如果看 Expanded 和 None 类,会创造它们又继续自 jar。

末了,我们大略看一下 RepackageMojo 中的 repackage 调用所获取的 Repackager 的repackage 方法。
Repackager 中 repackage 方法源码如下。

public void repackage(File destination, Libraries libraries, LaunchScript 1aunchScript) throws IOException {//校验目标文件F (destination == null| | destination. isDirectory())throw new illegalArgumentException("Invalid destination");//校验依赖库f (libraries = null) {throw new IllegalArgumentException("Libraries must not be nu1l");//校验是否存在对应的 Layout, 如果不存在则创建if (this.layout == null) {this. layout = getL ayoutFactory() . getLayout(this . source);destination = destination. getAbsoluteFile();File workingSource = this. source;//检讨是否已经重新打包if (alreadyRepackaged() && this. source.equals(destination)) {//如果目标文件和 source 相同, 则删除原有备份文件( . original 结尾的), 重新备份 source 文件if (this. source . equals(destination)) {workingSource = getBackupFile();workingSource. delete();renameFile(this. source, workingSource);destination. delete();try {try (JarFile jarFileSource = new JarFile(workingSource)) {//核心功能便是创建 JarWriter 向文件指定文件中写入内容repackage(jarFileSource, destination, libraries, launchScript); }finally {if (!this . backupSource && !this. source . equals (workingSource)) {deleteFile(workingSource);}}}

上述代码的核心业务逻辑如下。

.校验各种参数(文件和路径是否存在)。

.备份待重新打包的文件以.original 结尾, 如果已经存在备份文件则先实行删除操作。

:天生目标文件之前,先打消一下目标文件。

调用重载的 repackage 方法,进行详细(jar 包)文件的天生和 MANIFESTMF 的信息写入。

.末了,判断并实行 workingSource 的打消操作。

用一句话总结上述过程:当符合条件时,对原有 jar 包文件进行备份,并天生新的可以通过 jar-jar 启动的文件。

关于重新打包的 jar 的目录构造及 MANIFEST.MF 文件中的信息,我们将不才一节进行讲解。

jar包的构造

在上一节中,通过 spring-boot-maven-plugin 生 成了可实行的 jar 包,下面剖析-下 jar 包spring-learn-0.0.1-SNAPSHOT.jar的目录构造。

在上述构造中,BOOT-INF/classes 目录中存放业务代码,BOOT-INF/ib 目录中存放了除java 虚拟机之外的所有依赖; org 目 录中存放了 Spring Boot 用来启动 jar 包的干系 class文件; META-INF 目录中存放了 MANIFEST.MF、maven 信息和 spring factories 文件。

个中,Manifest.MF 文件常日被用来定义扩展或档案打包干系数据,它是一个元数据文件,数据格式为名/值对。
一个可实行的 jar 文件须要通过该文件来指出该程序的主类。

Manifest-Version: 1.0Implementation-Title: spring-learnImplementation-Version: 0. 0.1-SNAPSHOTStart-Class: com. secbro2. learn. SpringLearnApplicationSpring - Boot-Classes: B0OT-INF/classes/Spring-Boot-Lib: B0OT-INF/lib/Build-Jdk-Spec: 1.8Spring- Boot -Version: 2.2.1. RELEASECreated-By: Maven Archiver 3.4.0Main-Class: org. springframework . boot . loader .Jarlauncher

Manifest.MF 文件中定义 Main-Class 设置为org. springframework.boot.loader.JarLauncher, 也 就 是 说 , jar 包 程 序 启 动 入 口 为JarL .auncher 类的 main 方法。
JarLauncher 类位 于 spring-boot-loader 项目中,在 jar 包的 org 目录中便存储着 Launcher 干系类的 class 文件。

项目的弓导类定义在 Start-Class 属性中,须要把稳的是,Start-Class 属性并非 Java 标准的 Manifest.MF 属性。

本文给大家讲解的内容是SpringBoot打包支配解析:jar包的天生和构造下篇文章给大家讲解的是SpringBoot打包支配解析:Launcher实现事理;以为文章不错的朋友可以转发此文关注小编;感谢大家的支持!
标签:

相关文章

今日头条算法如何实现个化推荐与精准传播

信息传播方式发生了翻天覆地的变化。今日头条作为国内领先的信息分发平台,凭借其强大的算法推荐系统,吸引了海量用户。今日头条的算法究竟...

Web前端 2025-01-31 阅读1 评论0

今日头条算法关闭之谜内容分发新格局

今日头条作为一款备受瞩目的新闻资讯平台,凭借其独特的算法推荐机制,吸引了大量用户。近期有关今日头条算法关闭的消息引发了广泛关注。本...

Web前端 2025-01-31 阅读1 评论0

今日头条算法智能推荐背后的科技魅力

信息爆炸的时代已经到来。人们每天在互联网上接触到海量的信息,如何从中筛选出有价值的内容,成为了人们关注的焦点。今日头条作为一款智能...

Web前端 2025-01-31 阅读1 评论0

今日头条算法专利申请个化推荐的秘密武器

信息爆炸的时代已经来临。在众多信息中,如何快速找到自己感兴趣的内容成为了一个难题。今日头条作为中国领先的资讯平台,凭借其独特的算法...

Web前端 2025-01-31 阅读1 评论0

今日头条算法机器推荐模式的秘密与挑战

大数据、人工智能等新兴技术的应用已经渗透到我们生活的方方面面。在信息爆炸的时代,人们获取信息的渠道越来越丰富,如何在海量信息中找到...

Web前端 2025-01-31 阅读1 评论0