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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35002.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35002.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35002.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

北京崇文門中醫醫院賈英才主任:腦梗治療新探索

腦梗&#xff0c;是眾多患者心中的陰霾&#xff0c;它的突然來襲&#xff0c;常常讓人猝不及防。 一旦發作&#xff0c;偏癱、失語等癥狀接踵而至&#xff0c;給患者及其家庭帶來沉重的打擊&#xff0c;極大地影響了生活的質量。 造成腦梗頻發的原因究竟是什么&#xff1f;中…

Golang | Leetcode Golang題解之第173題二叉搜索樹迭代器

題目&#xff1a; 題解&#xff1a; type BSTIterator struct {stack []*TreeNodecur *TreeNode }func Constructor(root *TreeNode) BSTIterator {return BSTIterator{cur: root} }func (it *BSTIterator) Next() int {for node : it.cur; node ! nil; node node.Left {it…

Docker部署前端,動態配置后端地址

本文介紹了使用Docker環境變量動態配置nginx。采用的是通過docker run -e xxxxxxx先往容器注入環境變量&#xff0c;然后進一步通過envsubst指令將環境變量寫入到conf文件中&#xff0c;實現動態配置文件內容。 背景 前后端分離的架構下&#xff0c;經常會用到nginx反向代理來…

粉末冶金5G智能工廠工業物聯數字孿生平臺,推進制造業數字化轉型

粉末冶金5G智能工廠工業物聯數字孿生平臺&#xff0c;推進制造業數字化轉型。在數字化浪潮席卷全球的今天&#xff0c;制造業的數字化轉型已然成為不可逆轉的趨勢。粉末冶金行業&#xff0c;作為制造業的重要一環&#xff0c;亦需緊跟時代步伐&#xff0c;以5G智能工廠、工業物…

【SpringSecurity】認證與鑒權框架SpringSecurity——授權

目錄 權限系統的必要性常見的權限管理框架SpringSecurity授權基本流程準備腳本限制訪問資源所需權限菜單實體類和Mapper封裝權限信息封裝認證/鑒權失敗處理認證失敗封裝鑒權失敗封裝配置SpringSecurity 過濾器跨域處理接口添加鑒權hasAuthority/hasAnyAuthorityhasRole/? hasA…

華為HCIP Datacom H12-821 卷10

1.多選題 以下哪些動態路由協議可以應用在 IPv6 網絡? A、Is- Is B、BGP6 C、IS-ISv6 D、OSPFv3 正確答案: A,D 解析: 幾乎每個動態路由協議都支持IPv6,但是每個協議支持IPv6的時候的叫法不相同。支持IPv6的RIP協議,叫做RIPng;支持IPv6的OSPF協議,叫做OSPFv3;支持…

針對知識圖譜使用 Mistral-7b 從簡歷中提取實體

翻譯&#xff1a;“Entity Extraction from Resume using Mistral-7b for Knowledge Graphs” | by Tejpal Kumawat | Feb, 2024 | Medium[1] 在快速發展的自然語言處理&#xff08;NLP&#xff09;領域&#xff0c;從非結構化文本源中準確提取和分析信息的能力變得越來越重要。…

Python教程:認識一下print函數

print() 是 Python 中一個非常基礎但功能強大的函數&#xff0c;用于將數據輸出到標準輸出&#xff08;通常是控制臺&#xff09;或文件。本文我們一起聊一下這個“平凡”的print函數。 原理 print() 函數的原理相對簡單&#xff0c;它接受一個或多個參數&#xff0c;并將這些…

ravynOS 0.5.0 發布 - 基于 FreeBSD 的 macOS 兼容開源操作系統

ravynOS 0.5.0 發布 - 基于 FreeBSD 的 macOS 兼容開源操作系統 ravynOS - 一個旨在提供 macOS 的精致性和 FreeBSD 的自由度的操作系統 請訪問原文鏈接&#xff1a;https://sysin.org/blog/ravynos/&#xff0c;查看最新版。原創作品&#xff0c;轉載請保留出處。 作者主頁…

snakeyaml從1.x升級2.x的方案

一、背景 因公司漏洞掃描&#xff0c;發現SnakeYAML 反序列化漏洞(CVE-2022-1471)&#xff0c;所以要求對SnakYaml進行升級。 因項目中未直接引用snakyaml包&#xff0c;經分析是springboot引用的這個包。但是在這個項目中&#xff0c;springboot用的版本是2.3.12.RELEASE版本…

睡眠剝奪對記憶鞏固的神經生物學影響

近期&#xff0c;《自然》雜志刊載的研究揭示了睡眠不足對記憶相關神經信號的不利影響&#xff0c;強調了即使在后續恢復充分睡眠的情況下&#xff0c;這種損害亦難以完全逆轉。 神經元作為大腦的基本功能單位&#xff0c;其活動并非孤立進行&#xff0c;而是通過復雜的網絡連接…

QT拖放事件之四:自定義拖放操作-利用QDrag來拖動完成數據的傳輸-案例demo

1、核心代碼 #include "Widget.h" #include "ui_Widget.h" #include "MyButton.h"Widget::Widget(QWidget *parent): QWidget

CSS3 分頁

CSS3 分頁 分頁是網頁設計中常見的一種布局方式&#xff0c;它允許將內容分布在多個頁面中&#xff0c;從而提高用戶體驗和網站的可管理性。CSS3 提供了多種靈活的方式來設計分頁&#xff0c;使得開發者能夠創建既美觀又實用的分頁導航。本文將詳細介紹如何使用 CSS3 來創建和…

python 正則表達式提取字符串

以某個字符開始、某個字符結束&#xff0c;期待的提取結果包含首末字符串 提取公式&#xff1a;a re.findall(“開始字符串.*末字符串”,str) 以某個字符開始、某個字符結束&#xff0c;期待的提取結果不包含末字符串&#xff0c;但包含首字符串 提取公式&#xff1a;a re.…

Cesium--旋轉3dtiles

以下代碼來自Cesium 論壇&#xff1a;3DTileset rotation - CesiumJS - Cesium Community 在1.118中測試可行&#xff0c;可直接在Sandcastle中運行&#xff1a; const viewer new Cesium.Viewer("cesiumContainer", {terrain: Cesium.Terrain.fromWorldTerrain()…

機器學習課程復習——線性回歸

Q&#xff1a;回歸和分類的區別&#xff1f; 回歸是連續的&#xff0c;分類是離散的 Q:用最小二乘法對線性回歸模型進行參數估計思路 例題

排序。。。

1. 掌握常用的排序方法&#xff0c;并掌握用高級語言實現排序算法的方法&#xff1b; 2. 深刻理解排序的定義和各種排序方法的特點&#xff0c;并能加以靈活應用&#xff1b; 3. 了解各種方法的排序過程及其時間復雜度的分析方法。 編程實現如下功能&#xff1a; &#xff08;1…

Makefile中error函數的用法

在 Makefile 中&#xff0c;error 函數是一個特殊的函數&#xff0c;用于在執行過程中生成一個錯誤消息并終止 Makefile 的執行。它的基本語法如下&#xff1a; $(error error-message)其中&#xff0c;error-message 是一個字符串&#xff0c;表示要顯示的錯誤消息。當 Makef…

vue+three.js渲染3D模型

安裝three.js: npm install three 頁面部分代碼&#xff1a; <div style"width: 100%; height: 300px; position: relative;"><div style"height: 200px; background-color: white; width: 100%; position: absolute; top: 0;"><div id&…