最近在项目中使用Maven遇到一个问题,明明传递依赖进来的是最新版本,但引用的还是旧版本。原来在parent pom
中的dependencyManagement
里指定了一个低版本的依赖,然后传递依赖的包版本就是低版本了。
在Maven官方文档中Introduction to the Dependency Mechanism有一段话:
Dependency management - this allows project authors to
directly specify the versions of artifacts to be used
when they are encountered in transitive dependencies or
in dependencies where no version has been specified.
大概意思是:
pom文件中没有指定版本的依赖或是传递的依赖,如果在dependencyManagement中有指定此依赖版本,那就使用dependencyManagement中定义的版本号。
来一个例子看一下:
假设我pom中的依赖长这样:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
</dependencies>
通过mvn dependency:tree
看一下依赖树,传递依赖的包版本都是正确的:
现在在parent中的dependencyManagement加入:
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.13.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
再来看一下依赖树:
parent的dependencyManagement中spring boot 依赖的spring版本是4.3.17.RELEASE
,将5.0.1.RELEASE
的传递依赖进来的spring版本都指定成了4.3.17.RELEASE
。
包依赖版本不一致,在运行项目时就会有问题了,由此 dependencyManagement 是一个控制依赖包版本的利器,但也会带来一些问题,在排查jar包冲突的时候尤其要注意。
还有一个要注意的是在parent里定义的依赖scope会影响到传递进来的依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
继承这个parent的pom里直接依赖或传递依赖servlet-api
,scope将是provided,然后你用 jetty 作为一个嵌入式容器启动的时候,会报找不到 servlet-api类的异常。provided 的语义是保证项目正常编译,但在运行项目main方法或打包成一个jar包时不会包含这个依赖。
如何解决
如果传递依赖的版本被 parent 中的 dependencyManagement 版本给覆盖了,那就直接在项目的最上层模块中把这个依赖引进来并指定版本。比如下面这个Spring Boot项目:
直接在红框里的 pom 文件引入对应的传递依赖,这个模块是 Spring Boot 运行 main 方法的模块,maven 在打包的时候,这个模块里直接引入的依赖优先级都是最高的,其它项目也类似。
参考Maven 父pom中dependencyManagement版本优先级高于传递依赖版本
maven的传递依赖与scope关系