01 引言
在复杂的聚合项目开发中,Maven依赖管理如同一把双刃剑。虽能简化模块协作,却也暗藏"依赖传递丢失"的隐形陷阱。
开发者常陷入这样的困境:明明依赖树完整无误,代码编译成功,却在运行时因缺少某个底层库而崩溃;单元测试顺利通过,生产环境却因ClassNotFoundException意外宕机。更令人头疼的是,这类问题往往潜伏在聚合项目的依赖迷宫中,由版本覆盖、隐式排除或父子POM配置冲突悄然触发。
当项目规模膨胀、团队协作加深,依赖链的断裂可能像多米诺骨牌般引发连锁反应,导致调试成本飙升,甚至威胁交付周期。本文将深入剖析Maven依赖传递失效的典型场景,揭示其背后的"元凶",并为你提供一套从预防到修复的全链路解决方案,助你摆脱依赖黑洞,重掌项目构建的主动权。
02 案例项目
先看项目的目录结构:
|-- maven-denpendency
|-- maven-common
|-- maven-dedc-parent
|-- maven-A
|-- maven-B
如图:
2.1 父级pom管理的依赖
maven-denpendency中主要的管理的maven依赖,其他省略
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>${forest.version}</version>
</dependency>
<dependency>
<groupId>com.simonking</groupId>
<artifactId>maven-common</artifactId>
<version>${maven-common.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
2.2 子集项目引用
maven-common项目的配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.simonking</groupId>
<artifactId>maven-denpendency</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.simonking</groupId>
<artifactId>maven-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>maven-common</name>
<description>maven-common</description>
<dependencies>
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
</project>
2.3 maven-common打包
使用IDEA的maven编译打包
mvn clean compile package
打包成功。如图:
2.4 问题发生
maven-A依赖maven-common,并使用了maven-common中的方法。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.simonking</groupId>
<artifactId>maven-dedc-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.simonking</groupId>
<artifactId>maven-A</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>maven-A</name>
<description>maven-A</description>
<dependencies>
<dependency>
<groupId>com.simonking</groupId>
<artifactId>maven-common</artifactId>
</dependency>
</dependencies>
</project>
使用的方法:
package com.simonking.maven;
import com.google.common.collect.Lists;
import java.util.ArrayList;
/**
* TODO
*
* @Author: ws
* @Date: 2025/2/25 17:39
*/
public class Test {
private ArrayList<Object> objects = Lists.newArrayList();
}
打包报错:
明明已经引入,但是maven-A 打包的时候就会报错:程序包com.google.common.collect不存在。
2.5 问题讨论
maven-common中的依赖为什么没有传递过来呢?本地的maven依赖关系明明已经传递过来了,为什么呢??
为什么打包就出现依赖丢失的问题?????
这种问题莫名其妙,感觉怎么都是对的。
guava版本已经在父级pom中已经定义好了,子项目都只是简单的引用,况且也不存在循环依赖的问题。我们使用最近比较火的
deepseek来帮我们分析一下原因。
因为deepseek 的回答里面有案例代码,比较繁多,所以这里也整理一下。
- 1、检查依赖的作用域(scope):如果依赖的
<scope>设置为test或provided,该依赖不会传递到其他模块。 - 2、确认子模块继承父pom:子模块未正确继承父 POM 的依赖。
- 3、检查依赖版本冲突:多个模块或依赖声明了相同库的不同版本,Maven 会按“最近原则”选择版本。
- 4、确保模块间依赖正确:模块 A 依赖模块 B,但模块 B 未正确声明对模块 C 的依赖,导致模块 A 无法间接获取模块 C 的依赖。
- 5、检查本地仓库和远程仓库:本地仓库损坏或远程仓库不可访问,导致依赖未正确下载
- 6、确保聚合项目结构的正确:父 POM 未正确聚合子模块
- 7、使用
<optinal>false</optional>:依赖被标记为<optional>true</optional>,导致不会传递。
同时deppseek 也总结了步骤:
2.6 问题分析
deepseek给出了排除错误的思路,我们需要排查项目的出现这个问题的原因
在实际的业务项目中,由于引入的maven 依赖比较多,如果版本管理 没有做好,会给项目问题的排查带来更大的难度。演示案例的难度大大减小了。
根据deepseek 提供的思路,依赖排查了作用域、父子项目继承关系、本地仓库和远程仓库的配置、模块的依赖关系optional 的配置等均没有发现问题。
业务项目中打包使用因为某一个API引用导致,此处maven-common 为例。我们使用分析一下maven-common 打包的结果。使用mvn dependency:tree 来分析一下。
这个报错复现了打包的异常。使用``maven-common 时,没有正确打包导致guava` 没有被正确打包,导致问题的发生。
2.7 问题解决
既然是maven-common 没有正确打包,那么是什么原因导致没有打进去呢。排除了配置的问题后,就只剩下maven依赖的冲突了。我们使用本地Maven的冲突来查看一下:
果然,看到了jsr305的冲突,分别是forest-spring-boot-starter和guava 中引入的jsr305不同的版本导致的冲突。
那就解决冲突就好了,使用其中一个版本的即可。
喜欢的朋友关注我的微信公众号: