spring - 为什么我的项目中的库版本与它的父 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的父依赖,结果也符合我的预期。所以我猜父声明是关键,但为什么呢?
此致。
解决方案
这是因为 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)
也许像这样..?(请让我知道,如果我错过了理解)
推荐阅读
- reactjs - 事件监听器反应钩子中的状态更新
- python - 制作一个有周期表的程序
- spring-boot - 您可以使用地图而不是内存数据库来存储数据吗?
- android - 如何使用 Ionic Capacitor 打包托管 Web 应用程序
- sql - INSERT 查询在 SQL 视图上运行,但不在 Visual Basic 中
- html - 如何使输入与背景图像一起使用?
- c# - JsonConvert.DeserializeObject 在.net 中不起作用
- c# - 3-Tier - 模型重用?
- stripe-payments - Stripe Checkout 服务器端加载客户卡
- javascript - 使用 NodeJS 通过 LDAP 身份验证获取用户个人资料图片