纯属想到想到想到哪里写哪里了,我单纯就是顺着我的思路写个杂谈,大伙看一乐就行
Maven笑传之藏藏bean
可能这个问题,大家不嗷嗷鼓捣 Maven,可能一辈子碰不上好几次,但是我还是要说说,要不然白摸索了))
一些通用的解决情况
孩子们,我是Maven,我又要找不到依赖了
实际上,有关于实际项目开发的过程中,因为 Maven 没法正常编译项目的原因,十个有八个会给你爆“找不到依赖”,这个问题藏的很深,而且那原因非常抽象,要么不知所云,要么你就不知道他为什么找不到。
如果你能通过先清除 IDEA
的缓存,然后经典三大步(clean
,complie
,package
)就好了
那其实都不是问题,只是 Maven 在它能访问的仓库里,没找到你声明的依赖信息(或完整文件)
再说另一种情况
在线或离线网络环境中拷贝maven
仓库到离线机器,使用maven
加载项目,maven
编译jar
包找不到或者提示jar
包信息不可用
然后我们进行了如下操作
- 常规
idea
的maven
设置,确保maven
的版本,配置文件
保持一致,maven仓库
可用 - 刷新
maven
操作,重试n次 maven
离线与 在线的切换(toggle offline mode),达到刷新maven
的目的pom
文件中针对加载不到jar包的依赖,删除,刷新maven
,再添加该依赖方式idea
重启idea
关闭项目,重新打开项目启动idea
缓存清除
其实这些都是常规操作,因为如果你用的是 IDEA 2024.2 之前的版本,确实存在这么一个bug,就是在你第一次开电脑开IDEA然后打开项目之后,这时候刷新了 Maven 是有概率找不到的,但是这不是你代码的问题,这时候甚至清除缓存都不好使
所以我鼓捣了很久才得知,关闭项目,重新打开项目启动就可以了
如果以上这些操作还不能解决,那就继续看下去吧,这是我群友告诉我的神秘小方法
- 首先就是找到
pom
文件中无法加载的依赖,所在maven
仓库的位置 - 找到最后一级目录之后,除了自身依赖的jar包和pom后缀的包之外,其他全部删除
- 项目中
pom
重新刷新,或者重复第一部分的步骤尝试解决
基本都可以解决
为什么 Maven 动不动就找不到依赖
Maven如何加载的依赖
所以上述我们可知 Maven 找不到依赖其实是一个特别玄学的问题,我们接下来分析一下这个问题产生的原因及其背后 Maven 的实现原理。
找不到依赖,那肯定存在一种情况就是真找不到了
Maven 管理依赖的核心逻辑是:通过 “GAV 坐标”(groupId、artifactId、version)唯一标识一个依赖,然后按固定流程从仓库中查找并加载依赖。任何一个写错都会导致 “找不到”,而且这三个缺一不可,很多人写多了 Spring Boot 他就不习惯写那个版本号了。这个流程可以这样理解
解析依赖坐标(GAV)
Maven 首先解析
pom.xml
中声明的dependency
标签,提取groupId
、artifactId
、version
三要素(缺一不可)。如果坐标中包含变量(如${project.version}
),会先通过 POM 继承、属性定义等方式替换为具体值,生成完整的 GAV。检查本地仓库
Maven 会优先检查本地仓库(默认路径
~/.m2/repository
)。本地仓库中,依赖按groupId/artifactId/version
的目录结构存储(例如org/springframework/boot/spring-boot-starter/2.7.5
)。如果目录下存在完整的依赖文件(.jar
、.pom
等),则直接使用;若不存在,进入下一步。查找远程仓库
若本地仓库缺失,Maven 会按配置的 “远程仓库顺序”(由
settings.xml
的<mirrors>
和pom.xml
的<repositories>
共同决定)依次请求远程仓库。远程仓库需返回该 GAV 对应的资源(通常是maven-metadata.xml
描述文件和实际的.jar
/.pom
)。下载并缓存到本地仓库
从远程仓库找到依赖后,Maven 会将其下载到本地仓库对应目录,并生成临时文件(如
.lastUpdated
记录下载状态)。下载完成后,临时文件会被清理,依赖标记为 “可用”。处理依赖传递与冲突
对于依赖 A 依赖的依赖 B(传递依赖),Maven 会自动解析并重复上述流程。若出现版本冲突,会通过 “就近原则”“声明优先” 等仲裁规则选择一个版本。
那我们写 Spring Boot 程序的时候,不写版本其实还是 starter 都搞好了,自动配置学长这招太狠了
至于版本,我只能说别信 IDEA 提示的那个, Maven 中央仓库 查是否存在该版本才是唯一标准
而且如果你没写 version,你就会发现你的 IDEA 项目“解体了”,包之间不会收缩,pom 下模块的所有类全部失效,变成咖啡杯,而且咋说都是你的类位置不正确,这时候如果你去移动你就输了,因为这是 Maven 抽风给 IDEA 整不会了,他就认定是你出错了,因为 IDEA 认为出事了赖你总比赖 Maven 来的轻松。
私有仓库(镜像)配置问题
还有一种情况,就是仓库里确实没有这个依赖,或者访问不到仓库
Maven 默认从中央仓库下载依赖,但是有时候,我们会布置自己线上的自己项目的 Maven 仓库,每个团队中的每个人都从这个仓库拉取依赖,我们会复制 setting.xml 到自己项目下然后修改设置为这个配置文件,这就是私有仓库。
而且私有仓库需要账号密码,但没在 settings.xml
的
<servers>
中配置认证信息,访问被拒绝,Maven 会假装
“没找到”。私有仓库必须配置对应的 <server>
认证信息。
那么就有依赖在于私有仓库不存在这种情况,我当时做项目就遇到过一次,我卡了三个小时,结果是真没有,我还记得那个项目是 apache 的那个 poi 依赖。
再比如配置了阿里云镜像,但镜像同步延迟,或者镜像地址写错了或者镜像挂掉了,Maven 镜像的本质就是我上面说的私有仓库,大公司可能改吧改吧就放出来了,这就来了镜像,国内镜像比较稳定的只有清华和阿里的,其他的基本半年几个月就换一次,这时候你再 compile,肯定就会因为找不到依赖而报错了。
依赖本身的问题导致的找不到
Maven 的编译行为是否会从仓库拉取依赖或进行比较,取决于依赖的版本类型(快照版 / 正式版)和本地仓库的依赖状态,也就是说,不一定有了依赖就是对的
什么是快照版本,就是 pom
文件包含-SNAPSHOT
的,一般我们自己创建项目默认都是-SNAPSHOT-0.0.1
。版本号不带-SNAPSHOT
,如2.7.5
、1.0.0.RELEASE
,这类版本一旦发布,内容理论上不会变更(视为
“稳定版本”)。
- 若本地仓库已存在该版本的完整依赖文件(
.jar
、.pom
等),Maven不会再从远程仓库拉取,也不会主动与远程仓库比较(默认认为本地文件是 “正确且最新的”)。 - 若本地仓库不存在,才会从远程仓库拉取并缓存到本地。
版本号带-SNAPSHOT
,如2.7.5-SNAPSHOT
,这类版本用于开发阶段,允许频繁更新(内容可能随时变化)。
即使本地仓库已存在该快照版本,Maven
默认会定期(默认每天一次)检查远程仓库是否有更新(通过比对maven-metadata.xml
中的时间戳)。
一句话,别用-SNAPSHOT
的依赖,一把情况下,只有自己定义
starter 才会出现这种情况,到时候你更新 starter
就会带来很多问题,所以我一直不提倡个人开发使用
starter,按那两下快捷键远比你因为更新导致各种需要改来的容易和稳定。
那么,若远程仓库(私有 / 公共)的依赖已删除,但本地存在,会怎样?
还是分两种情况
依赖是正式版本(Release)
- 理论上,原理上,正式版本的设计目标是 “一旦发布就永久可用”,Maven 假设本地缓存的正式版本是 “可信且完整的”,不会主动验证远程是否存在。所以 Maven 会正常使用本地仓库的依赖,不会报错,也不会去远程仓库检查(因为默认认为正式版本不会变更,本地存在即有效)。
- 理论上应该是这样,但是实际上,IDEA 自带的那个 Maven 插件非常狗屎,他会检查,他认为你依赖项假如远程没有了,那你用这个就是不安全的,他会阻止你,唉,事情还要从 结果由 Mend.io 提供技术支持 说起
那么如果你用的依赖是快照版本
- 若 Maven 触发了
“远程检查”(如到达默认的每日检查时间,或配置了
always
),会因远程仓库找不到该快照版本而报错(提示 “找不到依赖”);若未触发远程检查,则继续使用本地版本。 - 快照版本依赖远程仓库的元数据(
maven-metadata.xml
)来判断是否需要更新。如果远程仓库删除了该快照版本的所有文件(包括元数据),Maven 在检查时会发现 “远程无此版本”,即使本地存在,也会判定为 “依赖不可用”(因为快照版本的有效性依赖远程确认)。
本地依赖文件损坏或不完整找不到了
这种情况发生的不多,就是通常你没有配置镜像,而且你网络不好,没科学上网,就会下一半没下完,但是你就急着跑你那项目了,这时候依赖的拉取就会中断,爆出找不到依赖的错误,并且再也不会主动拉取
Maven
对本地仓库的文件完整性有严格校验,若文件损坏或下载中断,会被标记为
“不可用”,但目录结构仍存在,造成 “已下载”
的假象。那么你去看你的本地仓库,就会有.lastUpdated
临时文件。你删掉这个文件,Maven
就会重新拉取。
如果你项目文件损坏了(如jar
包被篡改),无论版本类型是正式版还是快照版:
- Maven 会判定本地依赖 “不可用”,尝试从远程仓库重新拉取。
- 若此时远程仓库也没有该依赖,则会报 “找不到依赖” 错误,即使本地存在物理文件。
而且别没事改你那 target 和 jar 包,因为 Maven
依赖校验用的是严格校(md5),每次跑项目 Maven
会校验依赖的md5
/sha1
哈希值,若本地文件被篡改(如手动替换jar
但未更新校验和文件),校验失败后会认为文件无效,视为
“未找到”。
还有一种小众情况,我群友跟我说,本地仓库目录被设置为 “只读”,Maven 就无法写入新下载的依赖,或无法读取已存在的依赖文件(尤其在 Linux/macOS 系统中)。
Spring Cloud 笑传之重出爆
依赖传递 “隐性缺失”,间接依赖被过滤
什么意思,也就是说,直接依赖能找到,但它依赖的 “间接依赖” 找不到。
依赖树出现了断裂,这个断裂通常都是悄悄断裂,因为我们用到多重依赖都是在基于 Spring Boot 下的 Spring Cloud 项目,依赖树会根部一步步上传,你自己声明了一个依赖,这个依赖 Spring Boot 自己也有,而且版本对不上,这时候 Maven 会拿你的依赖,这就很逆天了。
也就是,你破坏了依赖版本协调
Spring Boot 的依赖跟你某些依赖版本冲突,或者是依赖引入重复,starter 中的有的依赖你这也定义了,而且还声明了版本,这样就会隐性的导致冲突,而且你还不知道咋回事,而且这个报错是 Java 抛异常,Maven 是可能跑通的,所以很头疼。
因为 Spring Boot 的
starter(如spring-boot-starter-web
)本质是
“依赖包的集合”,所以其内部依赖的版本是经过 Spring
官方测试、确保相互兼容的,他官方要是冲突那大伙怎么用,出现了这个问题肯定是你的问题。
如果手动声明 starter
中已包含的依赖并指定版本,就会导致不同版本的类结构可能变化,这种情况下通常是编译时出现ClassNotFoundException
,或者NoSuchMethodError
。
Maven 会将重复的依赖纳入最终包中,虽然 Spring Boot
自己会处理这种情况,只不过处理的方式比较幽默,Maven
也会自动解析传递依赖,虽然也很幽默但是还有作用,它通过<exclusions>
排除、版本仲裁失败等情况。幽默的原因就是仲裁也会导致间接依赖缺失,比较好笑的一种情况就是版本仲裁选择了
“不存在的版本”,或者把你兼容的删了。
就算依赖没有直接出线问题,但冗余的声明会让依赖树变得混乱,这可能会让
Spring Boot
的自动配置出现问题,也就是通不过@ConditionalOnClass
(检查类是否存在)、@ConditionalOnResource
(检查资源是否存在)等注解使得依赖生效。
而且这种情况也会附带配置绑定失败,会出现BindException
,导致配置无法生效,因为
Spring Boot
的@ConfigurationProperties
会绑定依赖中的配置类。
版本冲突的报错往往
“不直接指向根源”,可能在启动时抛出NoClassDefFoundError
,但堆栈信息中看不到具体是哪个依赖版本导致的。如果他藏着,可能在运行时偶尔出现异常,你就会以为是你代码写错了
这种排查很麻烦,需要通过mvn dependency:tree
逐个排查冲突,标红的omitted for conflict
即冲突项。
这也就是为什么我们 Spring Cloud
开发的时候,必需统一版本,都会在pom.xml
的dependencyManagement
中继承spring-boot-dependencies
的版本(或覆盖指定),而非直接在dependencies
中声明。所有模块引入依赖时,默认使用<dependencyManagement>
中声明的版本,防止不同模块因
“各自声明不同版本” 导致的冲突。
而且这个东西比较神奇,若项目依赖 A,A 又依赖
B(传递依赖),<dependencyManagement>
中声明的 B
版本会覆盖 A 自带的 B 版本,确保项目中 B
的版本统一。而且在多模块项目中,父模块的<dependencyManagement>
可被所有子模块继承,子模块无需重复声明版本,实现
“一处配置,全项目生效”。
若伊框架在依赖的版本整理上极其出色,我截图给大伙看看


用<properties>
声明单个依赖的版本,然后<dependencyManagement>
管理基本所有能管理的,
<properties>
标签用于声明全局变量(通常是依赖版本号),本质是
“键值对存储”,方便在整个pom.xml
中统一引用和修改。将所有依赖的版本号定义在<properties>
中,修改时只需改一处,避免在多个依赖中重复修改版本(减少漏改风险)。
<dependencyManagement>
标签用于声明依赖的版本、范围等规则,但不会实际引入依赖(仅做
“版本约定”)。子模块或当前模块的<dependencies>
中声明依赖时,可省略版本号,自动继承<dependencyManagement>
中定义的版本。
Maven笑传之成(为)Charge(攻击) Bullseye(目标)

真恶心啊每次打开pom都是这一坨,天天就提供可传递易受攻击的依赖项 maven:org.yaml:snakeyaml:1.30 CVE-2022-1471 8.3 Deserialization of Untrusted Data CVE-2022-25857 7.5 Improper Restriction of Recursive Entity References in DTDs (‘XML Entity Expansion’) CVE-2022-38752 6.5 Out-of-bounds Write CVE-2022-38751 6.5 Out-of-bounds Write CVE-2022-38750 6.5 Out-of-bounds Write CVE-2022-38749 6.5 Out-of-bounds Write CVE-2022-41854 5.8 Out-of-bounds Write 结果由 Mend.io 提供技术支持
结果由 Mend.io 提供技术支持。。。。。。。。
Maven 变成现在这样十有八九都赖这个 Mend.io
这种问题一般都是很明显的,就是整个依赖都给你标黄,比较经典的就是
spring-boot-starter-web
依赖部分整体高亮
这就是著名的1.33问题,Provides transitive vulnerable dependency maven:org.yaml:snakeyaml:1.33
这个警告提示我们的Maven项目中使用了一个被认为是有漏洞的依赖项,并且这个依赖项也被其他依赖项所传递,所以 Mend 就认为你用这个依赖容易被攻击。
但是实际上攻击只要有人想,肯定是一直存在的,重点是我们怎么防御
解决这个问题就是尝试升级依赖项版本,如果有更新的版本可用,则可能已经修复了该漏洞,要不然也没招,但是通常会有新的漏洞)))
假如在新版本中,这个依赖已经解决了漏洞,那么我们可以升级依赖项版本,在Maven项目中,可以使用dependencyManagement
标签来管理依赖项。在这个标签中,可以指定一个特定版本,以便所有依赖项都将使用这个版本
最后,其实代码和应用程序环境能够安全地处理这个漏洞,你可以选择忽略警告
Lombok笑传之藏除bean
为什么王伟老师上课 lombok 依赖总是告诉你找不到 get set 方法,就是不让你继续编译,这个问题非常逆天
原因就是因为 lombok 依赖自己和 IDEA 插件 Lombok 有冲突的问题,和 Maven 关系还真不大
怎么办?其实我之前写过一个文章讨论这件事
https://ergoutreegal.cn/posts/42179.html
简单来说,换了一个适配的版本1.18.30
,然后清空下面的
build 标签中关于 lombok 的内容就可以
至于为什么这样,我推测了一下
无非就是可能是由于 Lombok 版本与 IDEA 插件、Maven 配置之间存在兼容性问题,这三中间出现了一对不兼容,导致注解处理异常。
我群友这么说的,高版本的 Lombok 引入了新特性或语法变更,与当前 IDEA 版本自带的 Lombok 插件不兼容,导致插件无法正确解析注解生成 getter 和 setter 方法。