首页 > 解决方案 > 为什么我的项目中的库版本与它的父 pom 声明不同?

问题描述

我简化了我的项目结构并找到了一些线索。我的项目结构如下所示:

-------- project 1 ---------
parent
     |_ project-a
        |_ src
        |_ pom.xml
     |_ pom.xml

------- project 2 ----------
project-b
     |_ src
     |_ pom.xml

---------------------------

在项目 1 中,parent 是 project-a 的 maven parent,它的 pom.xml 如下所示:

<?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 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- spring boot parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.demo</groupId>
    <artifactId>parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>A custom project using myfaces</name>
    <url>http://www.myorganization.org</url>

    <modules>
        <module>project-a</module>
    </modules>

    <dependencies>
    </dependencies>
</project>

在 parent 的 pom 中,它声明 spring boot 作为它的 maven parent 和 project-a 作为它的模块。在project-a中,它的pom如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>parent</artifactId>
        <groupId>com.demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>project-a</artifactId>
    <packaging>jar</packaging>
    <name>project-a Maven Webapp</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <testSource>1.8</testSource>
                    <testTarget>1.8</testTarget>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.0.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

project-b 是一个独立的项目,它的 pom 如下所示:

<?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 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- parent declaration is the key point of this problem! -->
    <parent>
        <artifactId>parent</artifactId>
        <groupId>com.demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <groupId>com.demo</groupId>
    <artifactId>project-b</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>A custom project using myfaces</name>
    <url>http://www.myorganization.org</url>

    <!-- Project dependencies -->
    <dependencies>
        <dependency>
            <groupId>com.demo</groupId>
            <artifactId>project-a</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <executable>true</executable>
                    <classifier>exec</classifier>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

通过mvn install安装项目 1 后,project-b 的依赖树如下:

[INFO] --- maven-dependency-plugin:3.1.1:tree (default-cli) @ project-b ---
[INFO] com.demo:project-b:jar:1.0-SNAPSHOT
[INFO] \- com.demo:project-a:jar:1.0-SNAPSHOT:compile
[INFO]    \- mysql:mysql-connector-java:jar:8.0.16:runtime

但是如果我删除project-b的pom中的父声明,project-b的依赖树就是我所期望的:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-b ---
[INFO] com.demo:project-b:jar:1.0-SNAPSHOT
[INFO] \- com.demo:project-a:jar:1.0-SNAPSHOT:compile
[INFO]    \- mysql:mysql-connector-java:jar:8.0.11:runtime

在重新安装项目1之后,我也尝试在项目1父的pom中删除spring boot的父依赖,结果也符合我的预期。所以我猜父声明是关键,但为什么呢?

此致。

标签: springmavenspring-boot

解决方案


这是因为 parent 的依赖比 project-a 的依赖具有更高的优先级。
你可以参考这个文档。
https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

  依赖中介——这决定了当遇到多个版本作为依赖时将选择哪个版本的工件。Maven 选择“最近的定义”。也就是说,它使用依赖关系树中与您的项目最接近的依赖关系的版本。您始终可以通过在项目的 POM 中明确声明来保证版本。请注意,如果两个依赖版本在依赖树中的深度相同,则第一个声明获胜。

  “最近的定义”意味着使用的版本将是依赖关系树中与您的项目最接近的版本。例如,如果 A、B 和 C 的依赖项定义为 A -> B -> C -> D 2.0 和 A -> E -> D 1.0,那么在构建 A 时将使用 D 1.0,因为从 A 开始的路径到 D 到 E 更短。您可以在 A 中显式添加对 D 2.0 的依赖项以强制使用 D 2.0。

<artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.6.RELEASE</version>

由于该模块还具有 mysql-connector-java(8.0.16) 的依赖项,因此 maven 使用它而不是 project-a 的依赖项。

https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent/2.1.6.RELEASE

project-b
parent
|----mysql-connector-java(8.0.16)   <- maven choose this because its level is higher
|----project-a
     |----mysql-connector-java(8.0.11)

也许像这样..?(请让我知道,如果我错过了理解)


推荐阅读