当前位置: 首页 > news >正文

spring boot jar 启动报错 Zip64 archives are not supported

spring boot jar 启动报错 Zip64 archives are not supported

  • 原因、解决方案
  • 问题
    • 为什么 spring boot 不支持 zip64
    • zip、zip64 功能上的区别
    • zip 的文件格式
    • spring-boot-loader 是如何判断是否是 zip64 的?
  • 参考

spring boot 版本是 2.1.8.RELEASE,引入以下 phoenix 依赖之后启动报错。

<dependency><groupId>org.apache.phoenix</groupId><artifactId>phoenix-client-hbase-2.4</artifactId><version>5.1.3</version>
</dependency>

错误日志:

PS D:\project\java\zip64\target> java -jar .\zip64-0.0.1-SNAPSHOT.jar
Exception in thread "main" java.lang.IllegalStateException: Failed to get nested archive for entry BOOT-INF/lib/phoenix-client-hbase-2.4-5.1.3.jarat org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:108)at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchives(JarFileArchive.java:87)at org.springframework.boot.loader.ExecutableArchiveLauncher.getClassPathArchives(ExecutableArchiveLauncher.java:69)at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
Caused by: java.io.IOException: Unable to open nested jar file 'BOOT-INF/lib/phoenix-client-hbase-2.4-5.1.3.jar'at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:258)at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:244)at org.springframework.boot.loader.archive.JarFileArchive.getNestedArchive(JarFileArchive.java:104)... 4 more
Caused by: java.lang.IllegalStateException: Zip64 archives are not supportedat org.springframework.boot.loader.jar.CentralDirectoryEndRecord.getNumberOfRecords(CentralDirectoryEndRecord.java:121)at org.springframework.boot.loader.jar.JarFileEntries.visitStart(JarFileEntries.java:117)at org.springframework.boot.loader.jar.CentralDirectoryParser.visitStart(CentralDirectoryParser.java:85)at org.springframework.boot.loader.jar.CentralDirectoryParser.parse(CentralDirectoryParser.java:56)at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:125)at org.springframework.boot.loader.jar.JarFile.<init>(JarFile.java:112)at org.springframework.boot.loader.jar.JarFile.createJarFileFromFileEntry(JarFile.java:289)at org.springframework.boot.loader.jar.JarFile.createJarFileFromEntry(JarFile.java:266)at org.springframework.boot.loader.jar.JarFile.getNestedJarFile(JarFile.java:255)

原因、解决方案

Google 很快就找到了原因,stackoverflow 上有类似的问题 java - Add more than 65535 entries jar in Spring boot - Stack Overflow。

第一个回答给出了原因:spring boot 不支持一个 jar 文件中多于 65534(这里应该写错了,应该是 65535) 个文件,并附上了抛异常的代码。

第二个回答是 spring boot 的 issues,有兴趣的可以自己看一下 Support zip64 format executable archives · Issue #2895 · spring-projects/spring-boot (github.com)

第三个回答给出了解决办法:升级到 2.2.x,也给出了支持 zip64 的提交记录 Support zip64 jars by cvienot · Pull Request #16091 · spring-projects/spring-boot (github.com)。我升级成 2.2.0.RELEASE 确实解决了问题。

image-20240625151243205

问题

回答一中的代码来自 spring-boot-loader 子项目中的 org.springframework.boot.loader.jar.CentralDirectoryEndRecord#getNumberOfRecords 方法,依赖如下:

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

为什么 spring boot 不支持 zip64

从 ZIP (file format) - Wikipedia 中可以看出 zip、zip64 在文件的格式上是不同的。猜测应该是开发者没想到 jar 包里的文件个数或 jar 包的大小会超过 65535,所以没有实现 zip64 相关的。从以下提交中能看出一二。直到最后的两个提交才有人实现了 zip64 的相关代码。

image-20240625173000853

zip、zip64 功能上的区别

zip64 格式是标准 zip 格式的扩展,实际上消除了 zip 存档中文件大小和数量的限制。

每种格式允许的最大值总结如下:

Standard FormatZip64 Format
Number of Files Inside an Archive65,5352^64 - 1
Size of a File Inside an Archive [bytes]4,294,967,2952^64 - 1
Size of an Archive [bytes]4,294,967,2952^64 - 1
Number of Segments in a Segmented Archive999 (spanning) 65,535 (splitting)4,294,967,295 - 1
Central Directory Size [bytes]4,294,967,2952^64 - 1

zip 的文件格式

zip格式压缩包主要由三大部分组成:数据区中央目录记录区(也有叫核心目录记录)中央目录记录尾部区

数据区是由一系列本地文件记录组成,本地文件记录主要是记录了压缩前后文件的元数据以及存放压缩后的文件

中央目录记录区是有一系列中央目录记录所组成,一条中央目录记录对应数据区中的一个压缩文件记录

中央目录记录尾部(End of central directory record)主要作用是用来定位中央目录记录区的开始位置,同时记录压缩包的注释内容

End of central directory record (EOCD)

OffsetBytesDescription[33]中文
04End of central directory signature = 0x06054b50签名
42Number of this disk (or 0xffff for ZIP64)
62Disk where central directory starts (or 0xffff for ZIP64)
82Number of central directory records on this disk (or 0xffff for ZIP64)
102Total number of central directory records (or 0xffff for ZIP64)文件数量(ZIP64 为 0xffff )
124Size of central directory (bytes) (or 0xffffffff for ZIP64)
164Offset of start of central directory, relative to start of archive (or 0xffffffff for ZIP64)
202Comment length (n)注释长度
22nComment

spring-boot-loader 是如何判断是否是 zip64 的?

// 从 bytes 的 offset 偏移量开始,以小端模式读取 length 个字节
public static long littleEndianValue(byte[] bytes, int offset, int length) {long value = 0;for (int i = length - 1; i >= 0; i--) {value = ((value << 8) | (bytes[offset + i] & 0xFF));}return value;
}
/*** A ZIP File "End of central directory record" (EOCD).** @author Phillip Webb* @author Andy Wilkinson* @see <a href="https://en.wikipedia.org/wiki/Zip_%28file_format%29">Zip File Format</a>*/
class CentralDirectoryEndRecord {// EOCD 最小长度,从表中可以看出在没有注释的情况下是 22private static final int MINIMUM_SIZE = 22;// 从表中可以看出注释长度为 2 字节,所有最大值是 65535private static final int MAXIMUM_COMMENT_LENGTH = 0xFFFF;private static final int MAXIMUM_SIZE = MINIMUM_SIZE + MAXIMUM_COMMENT_LENGTH;// EOCD 开始的标记private static final int SIGNATURE = 0x06054b50;// EOCD 中“注释长度”字段的偏移量,从表中可以看出是 20private static final int COMMENT_LENGTH_OFFSET = 20;// 每次从文件尾部读取 256 字节private static final int READ_BLOCK_SIZE = 256;// 最终是 EOCD 的字节数组private byte[] block;// EOCD 在 block 中的偏移量private int offset;// EOCD 的字节数private int size;/*** Create a new {@link CentralDirectoryEndRecord} instance from the specified* {@link RandomAccessData}, searching backwards from the end until a valid block is* located.* @param data the source data* @throws IOException in case of I/O errors*/CentralDirectoryEndRecord(RandomAccessData data) throws IOException {// 从文件尾部读取 256 字节this.block = createBlockFromEndOfData(data, READ_BLOCK_SIZE);this.size = MINIMUM_SIZE;this.offset = this.block.length - this.size;// 尝试找到 EOCD 的开头while (!isValid()) {this.size++;if (this.size > this.block.length) {if (this.size >= MAXIMUM_SIZE || this.size > data.getSize()) {throw new IOException("Unable to find ZIP central directory " + "records after reading " + this.size + " bytes");}// 每次多读 1 字节this.block = createBlockFromEndOfData(data, this.size + READ_BLOCK_SIZE);}// offset 每次向前移动 1 字节this.offset = this.block.length - this.size;}}private byte[] createBlockFromEndOfData(RandomAccessData data, int size) throws IOException {int length = (int) Math.min(data.getSize(), size);return data.read(data.getSize() - length, length);}// 尝试找到 EOCD 的开头private boolean isValid() {// 长度小于 EOCD 的最小长度,肯定不符合if (this.block.length < MINIMUM_SIZE// 读取 block 最开始的 4 个字节,与 EOCD 的标记进行比较,不符合则返回 false// 如果相等则找到了 EOCD 的开头|| Bytes.littleEndianValue(this.block, this.offset + 0, 4) != SIGNATURE) {return false;}// 读取注释长度 2 字节// Total size must be the structure size + commentlong commentLength = Bytes.littleEndianValue(this.block, this.offset + COMMENT_LENGTH_OFFSET, 2);// EOCD 的字节数肯定等于 EOCD 的最小长度 + 注释内容的长度return this.size == MINIMUM_SIZE + commentLength;}/*** Return the number of ZIP entries in the file.* @return the number of records in the zip*/public int getNumberOfRecords() {// 读取 block 偏移量文 10 的 2 个字节,即文件数量long numberOfRecords = Bytes.littleEndianValue(this.block, this.offset + 10, 2);// 如果文件数量为 65535 则为 Zip64if (numberOfRecords == 0xFFFF) {throw new IllegalStateException("Zip64 archives are not supported");}return (int) numberOfRecords;}}

参考

  • java - Add more than 65535 entries jar in Spring boot - Stack Overflow
  • 压缩包Zip格式详析(全网最详细)_zip格式详解-CSDN博客
  • ZIP文件格式分析 | Sp4n9x’s Blog
  • ZIP (file format) - Wikipedia

相关文章:

spring boot jar 启动报错 Zip64 archives are not supported

spring boot jar 启动报错 Zip64 archives are not supported 原因、解决方案问题为什么 spring boot 不支持 zip64zip、zip64 功能上的区别zip 的文件格式spring-boot-loader 是如何判断是否是 zip64 的&#xff1f; 参考 spring boot 版本是 2.1.8.RELEASE&#xff0c;引入以…...

BASH and SH in SHELL scripts

一、执行脚本的现象 为了测试一个小的功能&#xff0c;写了一个小脚本&#xff0c;类似的内容如下&#xff1a; #!/bin/shecho "start api test ......"for((i1;i<10;i)); do echo "cur id :" $i; done echo "end."执行一下&#xff0c;“…...

Qt Creator创建一个用户登录界面

目录 1 界面设计 2 代码 2.1 登录界面 2.2 注册界面 2.3 登陆后的界面 3 完整资源 这里主要记录了如何使用Qt Creator创建一个用户登录界面&#xff0c;能够实现用户的注册和登录功能&#xff0c;注册的用户信息存储在了一个文件之中&#xff0c;在登录时可以比对登录信息…...

等保测评练习卷14

等级保护初级测评师试题14 姓名&#xff1a; 成绩&#xff1a; 判断题&#xff08;10110分&#xff09; 1. 方案编制活动中测评对象确定、测评指…...

学懂C#编程:常用高级技术——学会C#多线程开发(三):学会线程池的使用

在C#中&#xff0c;线程池&#xff08;ThreadPool&#xff09;是一种用于管理线程的机制&#xff0c;它可以有效地重用线程&#xff0c;减少线程创建和销毁的开销&#xff0c;从而提高程序的性能。线程池通常用于执行不需要立即完成的任务&#xff0c;如后台任务、异步操作等。…...

maven-gpg-plugin插件

开源项目SDK&#xff1a;https://github.com/mingyang66/spring-parent 个人文档&#xff1a;https://mingyang66.github.io/raccoon-docs/#/ 一、敏感信息泄漏警告 执行mvn install或mvn deploy时控制台会报如下告警&#xff1a; [WARNING] Parameter passphrase (user pr…...

Linux——echo命令,管道符,vi/vim 文本编辑器

1.echo 命令 作用 向终端设备上输出字符串或变量的存储数据 格式 echo " 字符串 " echo $ 变 量名 [rootserver ~] # echo $SHELL # 输出变量的值必须加 $ /bin/bash [rootserver ~] # str1" 我爱中国 " # 自定义变量 echo 重定向输出到文件 ec…...

CISCN--西南半决赛--pwn

1.vuln 这是主函数&#xff0c;数一下就发现可以溢出最后的0x4008d0 然后会执行到这里&#xff0c;逻辑就是在v0上写shellcode&#xff0c;不过执行写0x10&#xff0c;不够sh&#xff0c;很明显要先read。 以下是exp: from pwn import * context.archamd64 ioprocess(./vuln)…...

DIYGW UniApp低代码可视化平台:高效、灵活、安全的应用开发新途径

一、引言 在数字化快速发展的今天&#xff0c;企业对于快速构建多端应用的需求日益增长。然而&#xff0c;传统的应用开发方式往往面临周期长、成本高、技术门槛高等问题。为了解决这些问题&#xff0c;DIYGW UniApp低代码可视化平台应运而生&#xff0c;它以高效率、多端使用…...

Python爬虫技术及其原理探秘

导言 随着互联网的发展&#xff0c;大量的数据被存储在网络上&#xff0c;而我们需要从中获取有用的信息。Python作为一种功能强大且易于学习的编程语言&#xff0c;被广泛用于网络爬虫的开发。本文将详细介绍Python爬虫所需的技术及其原理&#xff0c;并提供相关的代码案例。…...

堆和栈的区别及应用场景

堆和栈的区别及应用场景 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在计算机科学和编程领域&#xff0c;堆&#xff08;Heap&#xff09;和栈&#xff08…...

vant的dialog触发了其他overlay

原代码: <!-- dialog --><van-dialog v-model"showTipsDialog" title"温馨提示"><p>dialog内容</p></van-dialog><!-- overlay --><van-overlay style"display: flex" :show"showLoadingOverlay&q…...

Linux驱动开发笔记(十二)并发与竞争

文章目录 前言一、并发与竞争的引入1.1 并发1.2 竞争1.3 解决方法 二、原子操作2.1 概念2.2 使用方法 三、自旋锁3.1 概念3.2 使用方法3.3 自旋锁死锁 四、信号量4.1 概念4.2 使用方法 五、互斥锁5.1 概念5.2 使用方法 前言 Linux的子系统我们已经大致学习完了&#xff0c;笔者…...

【Mac】Listen 1 for Mac(最强的音乐搜索工具)软件介绍

软件介绍 Listen 1 for Mac 是一款非常方便的音乐播放软件&#xff0c;主要功能是集成多个音乐平台&#xff0c;让用户可以方便地搜索、播放和管理音乐。它是一个用 Python 语言开发的免费开源综合音乐搜索工具项目&#xff0c;最大的亮点在于可以搜索和播放来自网易云音乐&am…...

nginx 1024 worker_connections are not enough while connecting to upstream

现象 请求api响应慢&#xff0c;甚至出现504 gateway timeout&#xff0c;重启后端服务不能恢复&#xff0c;但重启nginx可以恢复。 解决方案 worker_connections使用了默认值 1024&#xff0c;当流量增长时&#xff0c;导致连接不够 在nginx.conf中修改连接数就可以了&…...

在Ubuntu 16.04上安装和配置Elasticsearch的方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 Elasticsearch 是一个用于实时分布式搜索和数据分析的平台。它因易用性、强大功能和可扩展性而备受欢迎。 Elasticsearch 支持 R…...

C#给SqlSugar封装一个单例类

.NET兼职社区 可以直接用&#xff0c;轻量方便&#xff0c;无需重复造轮子。 这里只对CRUD进行封装&#xff0c;我的应用比较简单。 using SqlSugar; using System.Collections.Generic;namespace MusicApp.Assist {internal class SqlSugarAssist{private static readonly ob…...

Postman接口测试工具的原理及应用详解(六)

本系列文章简介&#xff1a; 在当今软件开发的世界中&#xff0c;接口测试作为保证软件质量的重要一环&#xff0c;其重要性不言而喻。随着前后端分离开发模式的普及&#xff0c;接口测试已成为连接前后端开发的桥梁&#xff0c;确保前后端之间的数据交互准确无误。在这样的背景…...

【算法 之插入排序 原理及案例】

插入排序原理&#xff1a; 插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常…...

第一节:如何开发第一个spring boot3.x项目(自学Spring boot 3.x的第一天)

大家好&#xff0c;我是网创有方&#xff0c;从今天开始&#xff0c;我会记录每篇我自学spring boot3.x的经验。只要我不偷懒&#xff0c;学完应该很快&#xff0c;哈哈&#xff0c;更新速度尽可能快&#xff0c;想和大佬们一块讨论&#xff0c;如果需要讨论的欢迎一起评论区留…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...