Maven依赖传递同一个Jar在不同module中版本不同

Posted by 胡奚冰 on April 26, 2019

问题描述

今天遇到一个问题,情况是这样的:

项目是一个spring cloud架构,其中有两个module,一个是common通过maven依赖了某个jar,另一个是业务module,业务module依赖common,结构大致如下:

project
   -- common
      -- someJar: 3.14.0
   -- business
      -- common: 1.0

common中有一个使用someJar的util类,在common中Test运行正常,但是在business中运行却报错,提示someJar中的某个类找不到方法。

排查

首先查看了business的Dependencies发现了一个奇怪的现象:

business
    -- common: 1.0
        -- someJar: 3.6.0

business module的依赖树中someJar的版本被降低了。而util中使用新版本的方法,因此运行报错。

但又是什么原因造成这种情况的发生那?

一开始我认为这是一种不正常现象,可能是maven的缓存问题(之前使用过低版本的jar),但是经过多次clean并没有解决问题。

那肯定是找错了方向。

后来我又想到项目的maven设置parent来做版本管理,可以无需考虑版本适配的问题:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/>
    </parent>

之后就不需要显式声明版本号

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

会不会我使用的someJar已经在parent中定义了版本号?

我尝试把common中someJar显式声明的版本3.14.0去除,reimprot之后发现并没有提示缺少版本号,而且依赖树中看到的版本号就是3.6.0。已经明显了,问题的原因就是在依赖传递过程中someKar的版本被parent中定义的版本号覆盖了。

解决

找到了问题就好办了,我在common中指定版本号等于重写覆盖了以来的版本,但是在依赖传递的过程中,business并没有使用common中指定的版本,而是修正为parent中定义的版本。要解决这个问题有两种方法,一是:common中不指定版本号,使用parent定义的版本,但是不能使用新版本的方法。如果一定要使用新版本的方法,那另一种是:在business中也声明一个someJar的依赖,指定成新版本号,并且排除common中传递的依赖。

结论

对于parent中管理版本号的依赖jar来说,复写版本号只能在本module中生效,一旦依赖发生传递则会使用parent中定义的版本号。