V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
abcbuzhiming
V2EX  ›  Java

maven 的子模块依赖规则无法传导到父模块?

  •  
  •   abcbuzhiming · 1 天前 · 663 次点击
    最近实践中遇到了依赖冲突,在解决中无意中发现了下面这样奇怪的现象。

    问题一,项目主要靠 spring 启动,项目有两个模块,刚开始的时候,二者的 pom.xml 文件设置如下
    moudle-A
    |--moudle-B


    moudle-B
    |--lib1

    moudle-A 已经在依赖中添加了 moudle-B 。
    moudle-B 依赖 lib1 ,且 moudle 某个 service 在被 spring 初始化的时候,有一个 @PostConstruct 操作,这个操作会调用 lib1 中的类。

    问题现象,程序的启动入口在 moudle-A 中,一旦启动,就报在初始化那个 service 时找不到 lib1 中的类,项目跑不起来。解决办法很简单,把 moudle-A 的依赖改一下,改成下面这样:
    moudle-A
    |--moudle-B
    |--lib1

    就可以了。
    我的疑惑是 moudle-B 依赖 lib1 的这点无法传导给 moudle-A 吗? maven 的依赖规则是严格的按照 pom.xml 文件为单位隔离的吗?



    问题二:还是两个模块
    moudle-A
    |--moudle-B


    moudle-B
    |--lib1
    ----|--lib3 v1 (隐式依赖)
    |--lib2
    |--lib3 v2

    moudle-B 的 pom.xml 显式的依赖 lib1 ,lib2 ,lib3 v2 。
    lib2 拆包分析,自身没有定义依赖,但是需要 lib3 v2 才能运行起来。
    但是 lib1 自身依赖一个 lib3 v1 版本,于是就和 lib3 v2 冲突了。于是我只能编辑 moudle-B 的 pom.xml ,在 lib1 的依赖下显式的把 lib3 v1 给排除掉,像下面这样
    <dependency>
    <groupId>com.xxx</groupId>
    <artifactId>lib1</artifactId>
    <exclusions>
    <exclusion>
    <artifactId>lib3</artifactId>
    <groupId>com.yyy</groupId>
    </exclusion>
    </exclusions>
    </dependency>

    结果程序跑不起来,检查发现程序仍然在使用在使用 lib3 v1 版本,导致 lib2 无法启动,排除无效。后来用 maven 分析了一下,发现问题居然出现在 moudle-A ,moudle-A 引用 moudle-B 的时候,居然还是认为需要依赖 lib3 v1 。最后我没办法,我在 moudle-A 引用 moudle-B 的地方,把 lib3 排除掉了,然后自己加个新的 lib3.就像下面这样
    <dependency>
    <groupId>com.xxx</groupId>
    <artifactId>module-B</artifactId>
    <exclusions>
    <exclusion>
    <artifactId>lib3</artifactId>
    <groupId>com.yyy</groupId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>com.yyy</groupId>
    <artifactId>lib3</artifactId>
    <version>v2</version>
    </dependency>

    问题是解决了,但是这个方法真的是最佳方法吗?而且问题还是和第一个一样,maven 的父模块,是不检查子模块 pom.xml 文件内容的吗?子模块对依赖的一些定义设置,无法传导到父模块?
    6 条回复    2024-12-26 17:08:49 +08:00
    wxw752
        1
    wxw752  
       1 天前
    1. 你那个 module-B 在引入 lib1 的时候,scope 怎么写的? 是不是写了<scope>provided</scope>

    2. 两种可能,maven clean 一下试试,怀疑是 module-a 引用了 module-b 的缓存。第二种可能,module-a 里面除了 module-b 引用过 lib3 v1 ,还有其他包也依赖 lib3 v1 ,maven 依赖树中找到的最近版本是 v1 。
    不过可以肯定的是,那么写绝对不正常
    miaotaizi
        2
    miaotaizi  
       1 天前
    你要不把你的 pom.xml 复制给 ai 让 ai 帮你看看?

    按照你标题的描述我觉得能起作用才怪了。子模块里面的依赖为什么父模块要知道? 反过来, 父模块的依赖一定是能被子模块使用。
    PolarisY
        3
    PolarisY  
       19 小时 47 分钟前
    给你介绍个命令 mvn dependency:tree -Dverbose ,用用看你能发现什么。
    shangfabao
        4
    shangfabao  
       8 小时 45 分钟前
    你把
    moudle-B 的引用贴出来
    helloworld19
        5
    helloworld19  
       8 小时 33 分钟前
    👀
    abcbuzhiming
        6
    abcbuzhiming  
    OP
       4 小时 7 分钟前
    @wxw752
    1.没有写过这个 scope
    2.后面发现。还真是这个原因。


    @miaotaizi
    按照 maven 官方文档的说法,子模块的依赖是会传导进父模块的,所以父模块肯定知道子模块的依赖


    @PolarisY
    感谢你的这个命令,我是思维定式了,被困在 IDEA 这个 IDE 里提供的 maven help 提供的信息中。正是这个命令,让我发现了一件有趣的事情:
    +- (com.squareup.okhttp3:okhttp:jar:3.14.9:compile - version managed from 3.12.13; omitted for duplicate)
    明明,lib1 依赖的 okhttp 是 3.12.13 ,但是运行 mvn dependency:tree 后,显示 compile 时的依赖却是 3.14.9 。很显然,我原本以为这个依赖是 lib1 造成的,现在看 lib1 虽然要引用依 okhttp ,但是版本却不是它指定的。
    最后我顺藤摸瓜的找到了一个命令
    mvn help:effective-pom -Dverbose
    这个命令指出,module A 引用的另外一个 lib ,这个 lib 中,指定了 okhttp:jar:3.14.9 ,根据 maven 依赖冲突调解路径最近原则,maven 实际用了这个版本。

    所以,module B 不需要排除依赖,直接在 module A 中强制指定 okhttp 为 4.x ,根据路径最近原则,这个版本会强行覆盖 module B 中的 okhttp 依赖,于是问题终于解决了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3118 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 13:16 · PVG 21:16 · LAX 05:16 · JFK 08:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.