纯属想到想到想到哪里写哪里了我单纯就是顺着我的思路写个杂谈大伙看一乐就行

Maven笑传之藏藏bean

可能这个问题,大家不嗷嗷鼓捣 Maven,可能一辈子碰不上好几次,但是我还是要说说,要不然白摸索了))

一些通用的解决情况

孩子们,我是Maven,我又要找不到依赖了

实际上,有关于实际项目开发的过程中,因为 Maven 没法正常编译项目的原因,十个有八个会给你爆“找不到依赖”,这个问题藏的很深,而且那原因非常抽象,要么不知所云,要么你就不知道他为什么找不到。

如果你能通过先清除 IDEA 的缓存,然后经典三大步(cleancompliepackage)就好了

那其实都不是问题,只是 Maven 在它能访问的仓库里,没找到你声明的依赖信息(或完整文件)

再说另一种情况

在线或离线网络环境中拷贝maven仓库到离线机器,使用maven加载项目,maven编译jar包找不到或者提示jar包信息不可用

然后我们进行了如下操作

  • 常规 ideamaven设置,确保 maven的版本, 配置文件保持一致, maven仓库可用
  • 刷新 maven操作,重试n次
  • maven 离线在线的切换(toggle offline mode),达到刷新 maven的目的
  • pom文件中针对加载不到jar包的依赖,删除,刷新 maven,再添加该依赖方式
  • idea重启
  • idea关闭项目,重新打开项目启动
  • idea缓存清除

其实这些都是常规操作,因为如果你用的是 IDEA 2024.2 之前的版本,确实存在这么一个bug,就是在你第一次开电脑开IDEA然后打开项目之后,这时候刷新了 Maven 是有概率找不到的,但是这不是你代码的问题,这时候甚至清除缓存都不好使

所以我鼓捣了很久才得知,关闭项目,重新打开项目启动就可以了

如果以上这些操作还不能解决,那就继续看下去吧,这是我群友告诉我的神秘小方法

  1. 首先就是找到pom文件中无法加载的依赖,所在maven仓库的位置
  2. 找到最后一级目录之后,除了自身依赖的jar包和pom后缀的包之外,其他全部删除
  3. 项目中pom重新刷新,或者重复第一部分的步骤尝试解决

基本都可以解决

为什么 Maven 动不动就找不到依赖

Maven如何加载的依赖

所以上述我们可知 Maven 找不到依赖其实是一个特别玄学的问题,我们接下来分析一下这个问题产生的原因及其背后 Maven 的实现原理。

找不到依赖,那肯定存在一种情况就是真找不到了

Maven 管理依赖的核心逻辑是:通过 “GAV 坐标”(groupId、artifactId、version)唯一标识一个依赖,然后按固定流程从仓库中查找并加载依赖。任何一个写错都会导致 “找不到”,而且这三个缺一不可,很多人写多了 Spring Boot 他就不习惯写那个版本号了。这个流程可以这样理解

  1. 解析依赖坐标(GAV)

    Maven 首先解析pom.xml中声明的dependency标签,提取groupIdartifactIdversion三要素(缺一不可)。如果坐标中包含变量(如${project.version}),会先通过 POM 继承、属性定义等方式替换为具体值,生成完整的 GAV。

  2. 检查本地仓库

    Maven 会优先检查本地仓库(默认路径~/.m2/repository)。本地仓库中,依赖按groupId/artifactId/version的目录结构存储(例如org/springframework/boot/spring-boot-starter/2.7.5)。如果目录下存在完整的依赖文件(.jar.pom等),则直接使用;若不存在,进入下一步。

  3. 查找远程仓库

    若本地仓库缺失,Maven 会按配置的 “远程仓库顺序”(由settings.xml<mirrors>pom.xml<repositories>共同决定)依次请求远程仓库。远程仓库需返回该 GAV 对应的资源(通常是maven-metadata.xml描述文件和实际的.jar/.pom)。

  4. 下载并缓存到本地仓库

    从远程仓库找到依赖后,Maven 会将其下载到本地仓库对应目录,并生成临时文件(如.lastUpdated记录下载状态)。下载完成后,临时文件会被清理,依赖标记为 “可用”。

  5. 处理依赖传递与冲突

    对于依赖 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.51.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.xmldependencyManagement中继承spring-boot-dependencies的版本(或覆盖指定),而非直接在dependencies中声明。所有模块引入依赖时,默认使用<dependencyManagement>中声明的版本,防止不同模块因 “各自声明不同版本” 导致的冲突。

而且这个东西比较神奇,若项目依赖 A,A 又依赖 B(传递依赖),<dependencyManagement>中声明的 B 版本会覆盖 A 自带的 B 版本,确保项目中 B 的版本统一。而且在多模块项目中,父模块的<dependencyManagement>可被所有子模块继承,子模块无需重复声明版本,实现 “一处配置,全项目生效”。

若伊框架在依赖的版本整理上极其出色,我截图给大伙看看

image-20250922232554449
image-20250922232605829

<properties>声明单个依赖的版本,然后<dependencyManagement>管理基本所有能管理的,

<properties>标签用于声明全局变量(通常是依赖版本号),本质是 “键值对存储”,方便在整个pom.xml中统一引用和修改。将所有依赖的版本号定义在<properties>中,修改时只需改一处,避免在多个依赖中重复修改版本(减少漏改风险)。

<dependencyManagement>标签用于声明依赖的版本、范围等规则,但不会实际引入依赖(仅做 “版本约定”)。子模块或当前模块的<dependencies>中声明依赖时,可省略版本号,自动继承<dependencyManagement>中定义的版本。

Maven笑传之成(为)Charge(攻击) Bullseye(目标)

image-20250922214136002

真恶心啊每次打开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 方法。