聚合项目中部分Maven依赖不传递的问题分析及解决

198 阅读4分钟

01 引言

        在复杂的聚合项目开发中,Maven依赖管理如同一把双刃剑。虽能简化模块协作,却也暗藏"依赖传递丢失"的隐形陷阱。

        开发者常陷入这样的困境:明明依赖树完整无误,代码编译成功,却在运行时因缺少某个底层库而崩溃;单元测试顺利通过,生产环境却因ClassNotFoundException意外宕机。更令人头疼的是,这类问题往往潜伏在聚合项目的依赖迷宫中,由版本覆盖、隐式排除或父子POM配置冲突悄然触发。

        当项目规模膨胀、团队协作加深,依赖链的断裂可能像多米诺骨牌般引发连锁反应,导致调试成本飙升,甚至威胁交付周期。本文将深入剖析Maven依赖传递失效的典型场景,揭示其背后的"元凶",并为你提供一套从预防到修复的全链路解决方案,助你摆脱依赖黑洞,重掌项目构建的主动权。

02 案例项目

先看项目的目录结构:

|-- maven-denpendency
   |-- maven-common
   |-- maven-dedc-parent
       |-- maven-A
       |-- maven-B

如图:

1.png

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

image-20250225165428651

打包成功。如图:

image-20250225165637945

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();
}

打包报错:

image-20250225174932293

明明已经引入,但是maven-A 打包的时候就会报错:程序包com.google.common.collect不存在

2.5 问题讨论

maven-common 中的依赖为什么没有传递过来呢?本地的maven依赖关系明明已经传递过来了,为什么呢??

image-20250225175303447

为什么打包就出现依赖丢失的问题?????

这种问题莫名其妙,感觉怎么都是对的。guava 版本已经在父级 pom 中已经定义好了,子项目都只是简单的引用,况且也不存在循环依赖的问题。

我们使用最近比较火的 deepseek 来帮我们分析一下原因。

image-20250225171107191

因为deepseek 的回答里面有案例代码,比较繁多,所以这里也整理一下。

  • 1、检查依赖的作用域(scope):如果依赖的 <scope> 设置为 testprovided,该依赖不会传递到其他模块。
  • 2、确认子模块继承父pom:子模块未正确继承父 POM 的依赖。
  • 3、检查依赖版本冲突:多个模块或依赖声明了相同库的不同版本,Maven 会按“最近原则”选择版本。
  • 4、确保模块间依赖正确:模块 A 依赖模块 B,但模块 B 未正确声明对模块 C 的依赖,导致模块 A 无法间接获取模块 C 的依赖。
  • 5、检查本地仓库和远程仓库:本地仓库损坏或远程仓库不可访问,导致依赖未正确下载
  • 6、确保聚合项目结构的正确:父 POM 未正确聚合子模块
  • 7、使用<optinal>false</optional>:依赖被标记为 <optional>true</optional>,导致不会传递。

同时deppseek 也总结了步骤:

image-20250225171819788

2.6 问题分析

deepseek 给出了排除错误的思路,我们需要排查项目的出现这个问题的原因

在实际的业务项目中,由于引入的maven 依赖比较多,如果版本管理 没有做好,会给项目问题的排查带来更大的难度。演示案例的难度大大减小了。

根据deepseek 提供的思路,依赖排查了作用域、父子项目继承关系、本地仓库和远程仓库的配置、模块的依赖关系optional 的配置等均没有发现问题。

业务项目中打包使用因为某一个API引用导致,此处maven-common 为例。我们使用分析一下maven-common 打包的结果。使用mvn dependency:tree 来分析一下。

image-20250225173104046

这个报错复现了打包的异常。使用``maven-common 时,没有正确打包导致guava` 没有被正确打包,导致问题的发生。

2.7 问题解决

既然是maven-common 没有正确打包,那么是什么原因导致没有打进去呢。排除了配置的问题后,就只剩下maven依赖的冲突了。我们使用本地Maven的冲突来查看一下:

image-20250225175809426

果然,看到了jsr305的冲突,分别是forest-spring-boot-starterguava 中引入的jsr305不同的版本导致的冲突。

那就解决冲突就好了,使用其中一个版本的即可。

喜欢的朋友关注我的微信公众号:

公众号

wx