利用FatJar彻底解决Jar包冲突(一)
利用FatJar彻底解决Jar包冲突
- 序
- FatJar的加载与隔离
- ⼀、 FatJar概念
- ⼆、FatJar的加载
- 三、FatJar的隔离
- 四、隔离机制验证
- 五、 FatJar的定位
- 六、 打包注意点
序
今天整理旧电脑里的资料,偶然翻到大概10年前实习时写的笔记,之前经常遇到Java依赖冲突的问题,想通过这种方式彻底解决Java里的依赖冲突,现在回过头来看,不知道是不是有点幼稚,欢迎交流,请轻喷。
FatJar的加载与隔离
⼀、 FatJar概念
将⼀个jar和他所依赖的jar都打在⼀个包中,这个包即为FatJar。
如何打FatJar
-
使⽤ maven shade 插件
使⽤ maven shade 插件解压依赖的jar并和原⼯程class混在⼀起打包成⼀个jar。 优点:打包⽅式简单,之后加载也较容易。 缺点:⽬录多且乱,对于jar包中的配置⽂件不利于定位;对于内部依赖冲突这种打包⽅式会⾃动排除冲突,覆盖class⽂ 件,不利于排查jar包本身内部的冲突,如下图。
建议:如果能够忍受这么乱的⽬录可以使⽤这种⽅式,因为加载class的时候很⽅便。

-
使⽤ SpringBoot 提供的打包插件
由于SpringBoot打出来的jar可以直接启动,这个jar就是FatJar,所以可以使⽤ Spring Boot 提供的打包插件将依赖的jar直接 打进FatJar,如下图。
优点:通⽤,spring boot,pandora boot都是基于这种⽅式,很多问题都有现成的解决⽅案⽐如之后遇到的autoconfig注⼊问题,autoconfig 提供了针对fatjar注⼊的插件。⽬录⼲净明了,如下图。
缺点:由于原⽣jar的加载只⽀持⼀层加载,即⽆法加载 jarin jar ⾥的class,所以这个问题需要调研,但是既然使⽤的是 Spring Boot的打包⽅式,Spring Boot本身肯定已经解决了这个问题。
考虑到通⽤性与“美感”,下⾯针对这种打包⽅式来解决相应的问题。

⼆、FatJar的加载
fatjar与普通jar的区别就是它将依赖的jar也打进了jar包⾥的lib⽬录下,所以需要加载jarin jar。对于Jar⾥的资源,定义 以‘!/ʼ来分割。原始的JarFile URL只⽀持⼀个‘!/ʼ,如图。

通过阅读Spring Boot启动加载相关的源码,发现Spring Boot扩展了这个协议,让它⽀持多个‘!/ʼ,从⽽就可以表示jarin jar的 资源了,如图。

既然这样,我们就可以复⽤Spring Boot 的 加载⽅式,即通过继承spring boot的launcher,复⽤它的createClassLoader来构造LaunchedURLClassLoader。

三、FatJar的隔离
解决了加载的问题之后,就需要研究如何与依赖FatJar的应⽤(以下简称为“应⽤”)隔离了,因为我们最终的⽬标就是针对 应⽤和jar⾥同类名(全路径)的两个class都能够加载且不冲突。根据java classloader的委托加载机制,我们可以确定我们 的FatJarClassLoader所处的位置如下:

应⽤的classloader使⽤的是AppClassLoader,需要创建⼀个与它同级的ClassLoader即FatJarClassLoader,通过设置 LaunchedClassLoader的parent为AppClassLoader的parent即ExtensionClassLoader就可以了,这样两个ClassLoader就可以 像上图那样隔离。

四、隔离机制验证
FatJarClassLoader 构造完成之后,我们就可以验证⼀下到底能不能解决冲突了。
- 原理层⾯验证
验证代码如下:

输出结果如下:

可以看到 FatJarClassLoader 的 parent 为 ExtensionClassLoader,所以与AppClassLoader是同级的。String的ClassLoader为 空是由于BootStrapClassLoader是通过C++编写的,是最“底”层的ClassLoader。 - 实例验证-构造冲突
在⼆⽅包中添加⽇志依赖如下:

该版本的Logger是有trace⽅法的,我们在⼆⽅包中可以直接调⽤进⾏确认:

将⼆⽅包打成普通的jar包,在应⽤中依赖该jar包(conflict-b),同时也依赖⼀个低版本的⽇志包:

在应⽤中调⽤⼆⽅包中的某个⽅法,该⽅法内部会调⽤Logger的trace⽅法:

报错如下:

可⻅构造冲突已经成功了! - 实例验证-利⽤FatJar解决冲突
将⼆⽅包打成FatJar之后在应⽤中通过反射调⽤原来会冲突的代码,调⽤成功:


可⻅,⼆⽅包是通过隔离的⽅式加载的,加载的是⼆⽅包⾃带的⾼版本的Logger;⽽应⽤本身加载的还是⽼版本的 Logger。
五、 FatJar的定位
由于是在运⾏期加载FatJar,所以需要⼿动定位FatJar的位置,这边普通Java程序和Java Web 定位⽅式不同,⽬前只是同时 使⽤这两种⽅式进⾏加载,还没有其他更通⽤的解决⽅案。 当依赖⽅是普通 Java 程序时,所有依赖的jar包路径可以通过如下代码获得:

⽽当依赖⽅是Java Web 应⽤时,根据Tomcat 中应⽤的⽬录结构:

得到 jar 包路径的步骤为:
1. AppClassLoader.getResource(“/”).getPath()
2. 上溯并进⼊lib⽬录即可
六、 打包注意点
使⽤Spring Boot插件打出的FatJar是包含pom.xml 的,如下图:

可⻅pom⽂件位置和普通jar包的位置是⼀致的,这样的话应⽤maven其实是可以识别到FatJar的pom⽂件的,这样会将 FatJar依赖的jar包加⼊到应⽤⾥,还是需要⼿动排除冲突,这就跟我们的初衷不⼀致了。所以需要将pom⽂件在打包时排 除,如下代码:

相关文章:
利用FatJar彻底解决Jar包冲突(一)
利用FatJar彻底解决Jar包冲突 序FatJar的加载与隔离⼀、 FatJar概念⼆、FatJar的加载三、FatJar的隔离四、隔离机制验证五、 FatJar的定位六、 打包注意点 序 今天整理旧电脑里的资料,偶然翻到大概10年前实习时写的笔记,之前经常遇到Java依赖冲突的问题…...
Spring MVC笔记
01 什么是Spring MVC Spring MVC 是 Spring 框架中的一个核心模块,专门用于构建 Web 应用程序。它基于经典的 MVC 设计模式(Model-View-Controller),但通过 Spring 的特性(如依赖注入、注解驱动)大幅简化了…...
BurpSuite插件jsEncrypter使用教程
一、前言 在当今Web应用安全测试中,前端加密已成为开发者保护敏感数据的常用手段。然而,这也给安全测试人员带来了挑战,传统的抓包方式难以获取明文数据,测试效率大打折扣。BurpSuite作为一款强大的Web安全测试工具,其…...
【C#实现手写Ollama服务交互,实现本地模型对话】
前言 C#手写Ollama服务交互,实现本地模型对话 最近使用C#调用OllamaSharpe库实现Ollama本地对话,然后思考着能否自己实现这个功能。经过一番查找,和查看OllamaSharpe源码发现确实可以。其实就是开启Ollama服务后,发送HTTP请求&a…...
Android Glide 框架线程管理模块原理的源码级别深入分析
一、引言 在现代的 Android 应用开发中,图片加载是一个常见且重要的功能。Glide 作为一款广泛使用的图片加载框架,以其高效、灵活和易用的特点受到了开发者的青睐。其中,线程管理模块是 Glide 框架中至关重要的一部分,它负责协调…...
每天记录一道Java面试题---day32
MySQL索引的数据结构、各自优劣 回答重点 B树:是一个平衡的多叉树,从根节点到每个叶子节点的高度差不超过1,而且同层级的节点间有指针相互连接。在B树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大…...
Vue3 Pinia 符合直觉的Vue.js状态管理库
Pinia 符合直觉的Vue.js状态管理库 什么时候使用Pinia 当两个关系非常远的组件,要传递参数时使用Pinia组件的公共参数使用Pinia...
深度学习与大模型基础-向量
大家好!今天我们来聊聊向量(Vector)。别被这个词吓到,其实向量在我们的生活中无处不在,只是我们没注意罢了。 1. 向量是什么? 简单来说,向量就是有大小和方向的量。比如你从家走到学校&#x…...
【网络编程】完成端口 IOCP
10.11 完成端口 10.11.1 基本概念 完成端口的全称是I/O 完成端口,英文为IOCP(I/O Completion Port) 。IOCP是一个异 步I/O 的 API, 可以高效地将I/O 事件通知给应用程序。与使用select() 或是其他异步方法不同 的是,一个套接字与一个完成端口关联了起来…...
《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)
目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功: 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具:Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...
管理网络安全
防火墙在 Linux 系统安全中有哪些重要的作用? 防火墙作为网络安全的第一道防线,能够根据预设的规则,对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问,只允许符合规则的流量进入系统,从而保护系统免受…...
明日直播|Go IoT 开发平台,开启万物智联新征程
在物联网技术飞速发展的当下,物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境,实现高效、便捷开发的有力工具。 3 月 11 日(星期二)19:00,GitCode 特别邀请独…...
系统架构设计师—系统架构设计篇—软件架构风格
文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格(数据共享风格)数据库系统黑板系统超文本系统 闭…...
【MySQL_04】数据库基本操作(用户管理--配置文件--远程连接--数据库信息查看、创建、删除)
文章目录 一、MySQL 用户管理1.1 用户管理1.11 mysql.user表详解1.12 添加用户1.13 修改用户权限1.14 删除用户1.15 密码问题 二、MySQL 配置文件2.1 配置文件位置2.2 配置文件结构2.3 常用配置参数 三、MySQL远程连接四、数据库的查看、创建、删除4.1 查看数据库4.2 创建、删除…...
【Zinx】Day5-Part4:Zinx 的连接属性设置
目录 Day5-Part4:Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4:Zinx 的连接属性设置 在 Zinx 当中,我们使用 Server 来开启服务并监听指定的端口,当接收到来自客户端的连接请求…...
【英伟达AI论文】多模态大型语言模型的高效长视频理解
摘要:近年来,基于视频的多模态大型语言模型(Video-LLMs)通过将视频处理为图像帧序列,显著提升了视频理解能力。然而,许多现有方法在视觉主干网络中独立处理各帧,缺乏显式的时序建模,…...
小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡
在微信小程序中,事件分为 冒泡事件 和 非冒泡事件 : 冒泡事件:当一个组件的事件被触发后,该事件会向父节点传递;(如果父节点中也绑定了一个事件,父节点事件也会被触发,也就是说子组…...
全球首款 5G-A 人形机器人发布
全球首款 5G-A 人形机器人于世界移动通信大会(MWC2025)上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍: 名称与背景 名称9:这款人形机器人名为 “夸父”,是中国移动、华为与乐聚机器人在 GTI 平台…...
Tomcat 新手入门指南
Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器,广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南,帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...
Flink-DataStreamAPI-生成水印
下面我们将学习Flink提供的用于处理事件时间戳和水印的API,也会介绍有关事件时间、流转时长和摄取时间,下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间,Flink需要知道事件时间戳,这意味着流中的每个元素都需要…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
