1. 这个报错的现场以及我为什么对1.8.13这个版本印象这么深先说场景你在本地跑一个Spring Boot项目本来好好的换了一台机器、更新了依赖或者让同事拉了一份代码一执行mvn clean package或者直接java -jar启动阶段就弹出一条很奇怪的异常java.lang.IllegalStateException: Unable to open nested entry BOOT-INF/lib/aspectjweaver-1.8.13.jar ... Caused by: java.util.zip.ZipException: Invalid CEN header (invalid zip64 extra data field size)更直接的情况是在IDE里展开External Libraries想点开aspectjweaver-1.8.13.jar看一眼里面的类结果整个目录树都打不开只有这句异常Invalid CEN header (invalid zip64 extra data field size)看到Invalid CEN header的时候很多人的第一反应是这jar是不是用了什么特殊压缩方式是不是JDK不兼容是不是zip64这种格式太新了其实都不是这句话翻译成人话就是——你拿到的这个jar文件已经损坏了ZIP格式的中央目录区里某个zip64扩展字段的长度值不对Java的zip解析器没法继续读下去。为什么这个报错会跟aspectjweaver-1.8.13绑在一起出现因为它实在太老了。1.8.13是AspectJ 1.8.x时代的一个常用版本很多老项目的pom.xml里直接写着这个版本号Spring Boot早期版本也会把它带进来。只要某个渠道上的文件出现截断、下载不完整或者被安全软件改动过这个版本就会中招。但注意这不是AspectJ自己的问题而是文件完整性的问题。这篇文章我会把ZIP结构讲清楚再给你一套可以照着操作的排查和修复步骤。适合谁看只要你在Maven/Gradle项目里碰到任何jar包出现Invalid CEN header、zip64 extra data field size这类字样都可以直接参考。如果你只是想知道怎么最快让项目跑起来直接跳到第4节如果你想把根因弄明白建议从第2节开始读。2. ZIP文件结构拆解CEN header和zip64扩展字段到底是干什么的既然报错点死在CEN header上就得先把ZIP文件格式聊透。很多开发写了几年Java天天跟jar包打交道却不一定清楚jar包内部到底是什么结构。2.1 一个jar包到底是怎么组织起来的jar包本质上就是一个ZIP压缩包ZIP格式允许把一个文件拆成三部分来看第一部分是一个个被压缩的文件条目每个条目前面有一个local file header记录这个条目自己的压缩方式、大小、CRC32校验值等信息紧接着是压缩数据。第二部分在文件末尾附近叫central directory也就是中央目录区。这里会把整个ZIP包中的所有条目再列一遍每条记录叫central directory file header简称CEN header。可以把它理解成书的目录页——你要找某个类、某个资源Java的ZipFile不是傻乎乎地从头扫到尾而是先到文件末尾附近找到中央目录区把目录读进内存。第三部分是End of Central Directory Record也就是目录区的结束标记它告诉解析器中央目录区从这里开始、到这里结束全包有多少个条目。所以Java读jar包时真正决定你能不能打开这个包的其实是中央目录区。如果CEN header的某个字段损坏ZipFile在构造阶段就会抛异常压根轮不到你读具体entry。2.2 CEN header里的zip64 extra data field size为什么这么关键ZIP格式最早是上世纪90年代定义的当时很多字段都用4字节存理论上能表达的范围有限。后来文件大了、条目多了就得靠ZIP64扩展来补在CEN header里如果原字段的值是0xFFFFFFFF这种特殊值解释器就要去后面的extra field里找ID为0x0001的ZIP64扩展块读取真正的8字节大小值、8字节偏移量等。ZIP64扩展块在中央目录中的标准结构大致是这个样子2字节Header ID必须是0x00012字节这个扩展块的总长度data size后面跟着变长内容可能包含未压缩大小、压缩大小、本地头部偏移和所在磁盘编号问题就出在那个总长度上。正常文件的这个长度应该严格等于可变内容实际所需的字节数。比如只需要记录未压缩大小和压缩大小那就是16字节再带上本地头部偏移就再加8字节。如果长度值和实际内容对不上Java的解析就会直接报invalid zip64 extra data field size。在你遇到的场景里报这个错几乎可以断定文件的中央目录区被写坏了或者文件被截断后读出来的长度字段是一堆垃圾值恰好被解析器判定为无效的zip64长度。不是zip64多高端而是zip64字段成为了一面照妖镜照出了文件损坏这个事实。2.3 一个不到几百KB的aspectjweaver怎么就跟zip64扯上关系了这是我被问得最多的一个问题。aspectjweaver-1.8.13.jar不大按理说用不到zip64的扩展数值范围。但ZIP格式有一个特点zip64扩展块的出现不一定是必须的有些打包工具会在特定条件下顺手写一个写得很规范Java也能正常读。而损坏文件则不同它可能是某一段字节整个偏移了、缺了、多了导致解析器在原本不该出现zip64扩展的地方看到了一个奇怪的extra field于是按zip64去解析结果长度值不合法。所以正确的思路不是去怀疑aspectjweaver-1.8.13是不是用了zip64导致兼容问题而是接受文件已经损坏这个基本判断然后按文件损坏去定位和修复。3. 完整的定位链路从一条异常到确认根因很多人拿到这个报错第一件事就是去改pom版本或者把整个~/.m2删了重新拉。这些动作不是不能做但如果不知道问题发生在哪个文件、哪个环节后面还会再踩坑。我通常按下面这套步骤来定位。3.1 先确认报错指向的jar文件到底在哪个路径日志或IDE里的报错一般会给出完整路径比如file:/home/you/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar先在本地仓库里把这个文件找到看它旁边有什么ls -l ~/.m2/repository/org/aspectj/aspectjweaver/1.8.13/正常目录下应该有aspectjweaver-1.8.13.jar、aspectjweaver-1.8.13.pom以及从中央仓库下载的sha1文件。如果目录里出现了*.lastUpdated、*.part或者只有0字节的jar基本可以确定是下载阶段出了问题。如果报错来自Spring Boot可执行jar路径会变成BOOT-INF/lib/aspectjweaver-1.8.13.jar这种形式。别急着去改target目录里的包核心动作还是回到Maven本地仓库检查源文件因为target里的坏包通常是从本地仓库复制过去的。3.2 用JDK自带工具给jar做一次“心电图”不要急着写代码先用命令行工具验证。JDK自带jar命令可以这样测jar tf /home/you/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar如果文件损坏这里的输出不会正常列出条目而是直接抛java.util.zip.ZipException: Invalid CEN header (invalid zip64 extra data field size)unzip命令也可以测unzip -t /home/you/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar它会逐条测试CRC输出error: Invalid CEN header (invalid zip64 extra data field size)这两个命令任何一个报错都把文件损坏从猜测变成了事实。如果unzip -t通过而jar tf却报错那一般是因为JDK的java.util.zip解析比原生unzip更严格说明文件存在不规范但刚好能被unzip容忍的字段这种情况建议也按损坏处理。3.3 用一段Java代码确认读取动作在哪一步断掉有时候命令行工具不报错但IDE打不开因为IDE使用的是Java的ZipFile。可以写一段最简单的Java程序测试Java 9以上可以把ByteArrayOutputStream删掉用OutputStream.nullOutputStream()import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Paths; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class ZipCheck { public static void main(String[] args) throws Exception { var file Paths.get(args[0]).toFile(); try (ZipFile zf new ZipFile(file)) { Enumeration? extends ZipEntry entries zf.entries(); while (entries.hasMoreElements()) { ZipEntry entry entries.nextElement(); try (InputStream in zf.getInputStream(entry)) { in.transferTo(OutputStream.nullOutputStream()); } System.out.println(OK: entry.getName()); } } } }运行java ZipCheck.jar /home/you/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar如果输出到某个条目时就停住或者构造ZipFile直接抛ZipException说明中央目录区已经读不完整了。坏文件不需要继续在上面浪费时间直接进入修复环节。3.4 对比官方校验值锁定根因环节确认文件损坏之后还差最后一步判断这个坏文件是本地独有的还是仓库上游也是坏的。以中央仓库为例可以在浏览器或命令行里拿它的SHA1curl -s https://repo1.maven.org/maven2/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar.sha1再算一下本地文件的SHA1shasum -a 1 ~/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar两个值如果不一样就说明本地文件确实是坏的。至于坏在哪个环节你可以再观察几个信号如果本地文件修改时间恰好是最近一次mvn执行的时间且大小比正常值小很多多半是Maven下载时断流。如果这个文件是从公司私服Nexus/Artifactory同步下来的私服上的远端缓存副本也可能损坏需要去私服管理界面清理对应仓库的缓存。如果文件大小正常但校验值就是不对要怀疑安全软件、网盘同步工具或者磁盘问题它们可能在后台对文件做了修改。到这里根因链路已经闭环Maven/工具链从某个仓库拿回了损坏的jarJava解析中央目录时发现了zip64扩展字段长度异常于是报错。知道根因之后修复就快多了。4. 让项目重新可用的四种解决路径按风险和成本排序下面是实际修复动作。我建议按路径一、路径二的顺序试因为在大多数情况下它们就够了。路径三和路径四解决的是上游也坏了和已经打进包里的变种场景。4.1 路径一清掉本地仓库里这个版本的缓存强制重新下载这是最标准、最不应该出错的修法。先把目标版本目录整个删掉rm -rf ~/.m2/repository/org/aspectj/aspectjweaver/1.8.13注意Windows下路径是C:\Users\你的用户名\.m2\repository\org\aspectj\aspectjweaver\1.8.13用文件管理器删或者用rd /s /q都行。然后执行构建命令带上强制更新快照参数mvn clean package -U关键点在于一定要把整个版本目录删掉而不是只删jar文件。因为Maven在解析元数据时还会参考.lastUpdated之类的失败标记文件如果你只删jar不删标记Maven可能认为这个版本刚刚拉取失败过在短时间内不会真的重新下载甚至继续报错。如果你只是想验证能不能从远端拿到好文件用mvn dependency:get单独拉一次最直接mvn org.apache.maven.plugins:maven-dependency-plugin:3.6.1:get \ -Dartifactorg.aspectj:aspectjweaver:1.8.13 \ -Dtransitivefalse拉完之后再跑一次jar tf ~/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar如果正常列出类文件说明本地修复成功。4.2 路径二绕过损坏来源手动从可选择仓库下载并安装到本地如果路径一执行后重新拉下来的文件还是坏的说明你的下载源有问题。可能是公司私服的缓存坏了也可能是中间网络/下载工具把文件改坏了。这时候可以明确指定一个可信仓库下载jar再手动安装进本地仓库。以Central仓库为例先手动下载curl -fL -o aspectjweaver-1.8.13.jar \ https://repo1.maven.org/maven2/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar下载完成后立刻校验shasum -a 1 aspectjweaver-1.8.13.jar如果它与官方发布的sha1一致再用Maven安装到本地仓库mvn install:install-file \ -Dfileaspectjweaver-1.8.13.jar \ -DgroupIdorg.aspectj \ -DartifactIdaspectjweaver \ -Dversion1.8.13 \ -Dpackagingjar安装后项目构建不需要再联网拉这个jar因为本地仓库已经有同名同版本的文件了。需要提示一下这操作只覆盖了本地如果其他同事也遇到那就是上游仓库问题应该去私服管理界面清理这个路径的缓存或者换一个可用的镜像仓库。4.3 路径三用排除传递依赖的方式替换成健康版本有些项目里aspectjweaver并不是直接在pom中声明的而是通过其他库传递进来的。这个时候你就算删了本地目录下一次构建还是会把它拉回来。想在不动整体依赖结构的情况下换掉它就要用exclusion。先看依赖树找到是谁带进来这个版本的mvn dependency:tree -Dincludesorg.aspectj:aspectjweaver假设输出显示是org.springframework.boot:spring-boot-starter-aop传递带来的那么在以它为主的依赖声明里排除掉这个老版本dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-aop/artifactId exclusions exclusion groupIdorg.aspectj/groupId artifactIdaspectjweaver/artifactId /exclusion /exclusions /dependency然后在dependencyManagement或直接声明里加入你想用的健康版本。如果只想最小改动可以先换成同一系列的更高版本比如1.8.14如果项目本身跑在Java 8及以上换到1.9.x系列也没问题它们对Spring AOP兼容得很好。换版本前最好跑一遍项目已有的测试和核心流程因为AspectJ不同小版本之间的织入行为可能会有一点点差异。至少验证三件事项目能编译、Spring容器能启动、带Aspect注解的切面日志能正常打印。4.4 路径四处理Spring Boot可执行jar里嵌套jar报错的特殊场景还有一类人遇到这个报错不是在IDE里而是启动一个已经打好的xxx.jar时java -jar my-app.jar ... Caused by: java.util.zip.ZipException: Invalid CEN header (invalid zip64 extra data field size) at java.util.zip.ZipFile.getEntry(ZipFile.java)这种情况下报错指向的是BOOT-INF/lib/aspectjweaver-1.8.13.jar——也就是说Spring Boot的fat jar确实把损坏的jar打进去了。这时候只修本地仓库还不够因为target目录下的旧包还残留着坏文件。修复步骤是按照路径一或路径二先把本地仓库的aspectjweaver修好。对项目执行一次彻底的mvn clean package。确认新生成的jar中嵌套的aspectjweaver大小正常可在新jar上用jar tf检查。再启动。如果项目是多模块或使用了增量构建建议加clean因为有些插件会在target里复用旧文件不会因为本地仓库更新而自动重打。我也遇到过一种情况本地仓库的jar已经验证通过但IDE里还是报错那是IDE缓存了旧的zip索引重启IDE或点击File - Invalidate Caches即可。5. 长期预防怎么避免下次再遇到同类损坏的jar包解决了当前报错后续还要防止复发。下面几个习惯是我在实际维护项目时养成的成本不高但很管用。5.1 给本地仓库里的关键jar定期做完整性自检不需要每次全量扫一遍那样太慢。通常只需要对出过问题的坐标目录做检查。如果你怀疑哪个jar有问题直接跑这条命令for j in $(find ~/.m2/repository/org/aspectj -name *.jar); do jar tf $j /dev/null 21 echo OK $j || echo CORRUPT $j done在CI环境里也可以加一个定期任务把常用依赖的目录扫描一遍哪个坏了一目了然。别小看这条命令很多玄学构建失败其实就是某个jar在不知不觉中坏了。5.2 警惕那些会在后台“碰”jar文件的工具我见过不止一次杀毒软件或安全终端在后台扫描jar文件扫描过程中对文件加了临时锁甚至把部分字节标记为隔离区导致Maven刚好在这个时间点读到半截文件。表现就是构建时好时坏报错内容还经常是奇怪的zip异常。如果你发现同一个jar反复损坏建议检查杀毒软件/EDR的实时扫描是否排除了~/.m2目录。本地仓库目录是否在网盘同步盘比如OneDrive目录、坚果云目录下面。同步盘在文件还没完全落盘时做了同步本地和云端版本互相覆盖就很容易得到损坏文件。是否使用了某些“加速下载”工具对jar做了代理缓存这类工具的缓存机制有时候会截断文件。把这些因素排除后问题才会真正消失。如果只是删了再下过几天又会复发。5.3 公司私服的缓存损坏比本地损坏更难发现如果你的项目依赖是从公司Nexus/Artifactory私服拉取的本地修复后再构建可能还是拿到坏文件。此时需要检查私服上对应路径的缓存在Nexus里定位org/aspectj/aspectjweaver/1.8.13/对比中央仓库的aspectjweaver-1.8.13.jar哈希。需要的话删除私服上这个路径的缓存让它下一次重新从上游同步。如果私服的上游代理也是某个内部镜像还要沿着代理链一层层往下查。注意私服清理缓存通常会影响团队内其他人最好在低峰期操作并且提前沟通。如果只想保当前构建路径二里的mvn install:install-file可以先把本地打上一个健康版本不与私服冲突。5.4 为什么我不建议一言不合就删除整个~/.m2本地仓库里可能有你花了很多天拉下来的几十个G依赖全删重建在弱网环境属于灾难。更重要的是全删后如果你公司的私服或镜像仍然有缓存问题坏的jar会被重新拉回来等于做无用功。正确姿势是定位到具体版本目录范围删除。比如这次只删org/aspectj/aspectjweaver/1.8.13再配合-U重新构建。如果牵扯到传递依赖用mvn dependency:tree确认涉及哪些坐标把相关的都一起处理避免一半修好一半没修好。6. 顺带聊一聊AspectJ版本选型以及我最后的实操体会版本选型这件事很多人在遇到这个报错时才第一次注意到aspectjweaver。1.8.13这个版本是2015年底发布的放到现在确实比较老。如果项目是新建的、运行在较新的JDK上直接使用1.9系列版本通常是更省心的选择。AspectJ 1.9系列对Java 8以上环境支持更好也修复了老版本里不少和字节码解析、module info相关的Edge Case。但如果你是接手一个存量项目我的建议是先确认报错根源是文件损坏再决定换不换版本。如果只是本地缓存坏换版本属于绕路反而可能引入不必要的兼容性风险。正确顺序永远是先校验文件完整性再清理并重新下载最后才考虑版本升级。替换版本后也不用做太多事但下面的自测清单值得跑一遍mvn clean package是否通过。项目启动日志是否出现AspectJ Weaver Version相关行。任意一个使用Aspect注解的切点是否正常工作。如果有使用Spring的EnableAspectJAutoProxy或XML配置确认没有因版本替换报找不到类的错误。我自己在实际操作中还有一个容易忽略的小细节当你用IDEA时Maven本地仓库里的文件被外部工具修复后IDEA可能不会立刻刷新。这时候不要着急怀疑修复步骤先在IDEA里执行一次Refresh All Maven Projects如果还不行就重启IDEA。这个动作有时候比改半天pom管用得多。关于文件完整性有一句我要反复强调碰到Invalid CEN header、invalid zip64 extra data field size不要看它带着zip64就以为是压缩格式的锅99%的情况是——你的jar文件已经不是它该有的样子了。把问题定性为文件损坏再按本文的顺序去定位、清理、重拉、验证基本都能解决。哪怕后面换了版本也建议把验证文件完整性的习惯保留下来毕竟在Java的世界里jar包是一切构建动作的起点起点坏了后面的每一步都会跟着出问题。