You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Maven测试依赖传递依赖覆盖编译依赖版本是否为Bug?

问题

项目存在如下依赖关系:

  • compile范围依赖链:B -> C -> guava-20.0
  • test范围依赖链:D -> guava-31.1

最终生成的生产Jar中却包含了guava-31.1。按预期测试依赖不应影响运行时类路径,但实际覆盖了Guava版本,这是Maven的Bug吗?

附实际场景POM示例:
Spring Eureka Client依赖guava-19.0,未添加wiremock依赖时,生产Jar中是guava-19.0;添加test scope的wiremock(依赖guava-32.1.3)后,生产Jar中的Guava版本变为32.1.3。

<?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>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.0</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mavendemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo1</name>
<description>demo1</description>
<properties>
    <java.version>17</java.version>
    <spring-cloud.version>2023.0.0</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.wiremock</groupId>
        <artifactId>wiremock</artifactId>
        <version>3.3.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
</project>
分析与解答

这不是Maven的Bug,核心原因是Maven的依赖调解规则和Spring Boot打包插件的行为共同作用的结果:

  1. Maven依赖调解的全局特性
    Maven在解析依赖版本时,会扫描**整个依赖树(包括test scope的依赖)**来进行版本选择,遵循"路径最近者优先",路径相同则"声明顺序优先"的规则。test scope的依赖虽然不会被加入运行时类路径,但会参与版本调解过程——它会影响最终选定的依赖版本,哪怕这个版本最终是被compile/runtime范围的依赖引用。

在你的场景中,wiremock引入的guava-32.1.3,依赖路径可能比Eureka Client的guava-19.0更短,或者在POM中声明顺序更靠后,所以Maven最终选定了guava-32.1.3作为全局版本。

  1. Spring Boot打包插件的行为
    Spring Boot Maven插件在打包生产Jar时,只会包含compile和runtime scope的依赖,但它会使用Maven已经调解好的版本——也就是刚才选定的guava-32.1.3,而不是Eureka Client原本依赖的19.0版本。

解决方案

  • 显式声明Guava版本:在POM的<dependencies>或<dependencyManagement>中直接声明guava的指定版本,强制Maven使用该版本,覆盖依赖调解的结果:
<dependencyManagement>
    <dependencies>
        <!-- 强制指定Guava版本 -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>
  • 排除test依赖中的Guava:在wiremock的依赖中排除guava,避免它参与依赖调解:
<dependency>
    <groupId>org.wiremock</groupId>
    <artifactId>wiremock</artifactId>
    <version>3.3.1</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </exclusion>
    </exclusions>
</dependency>

内容的提问来源于stack exchange,提问作者oceansize

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 10:57:35