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

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

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

    问题一,项目主要靠 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 文件内容的吗?子模块对依赖的一些定义设置,无法传导到父模块?
    8 条回复    2024-12-27 00:03:03 +08:00
    wxw752
        1
    wxw752  
       4 天前
    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  
       4 天前
    你要不把你的 pom.xml 复制给 ai 让 ai 帮你看看?

    按照你标题的描述我觉得能起作用才怪了。子模块里面的依赖为什么父模块要知道? 反过来, 父模块的依赖一定是能被子模块使用。
    PolarisY
        3
    PolarisY  
       4 天前   ❤️ 1
    给你介绍个命令 mvn dependency:tree -Dverbose ,用用看你能发现什么。
    shangfabao
        4
    shangfabao  
       3 天前
    你把
    moudle-B 的引用贴出来
    helloworld19
        5
    helloworld19  
       3 天前
    👀
    abcbuzhiming
        6
    abcbuzhiming  
    OP
       3 天前
    @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 依赖,于是问题终于解决了
    PolarisY
        7
    PolarisY  
       3 天前
    @abcbuzhiming 解决了明白了就好👍。不过用「排除」或「显式重写依赖」来解决版本问题不是正道,麻烦且会污染「排除」和「依赖」的语义。
    一般会建议在「根模块」使用 dependencyManagement 来统一管理版本,各子模块只要「按需引用」不再需要关注版本,不再需要「指定版本」或「排除内部引用」等方法解决版本问题。如果遇到深度内部引用的包有冲突,也只需要在「根模块」的 dependencyManagement 中指定该包的版本即可。
    abcbuzhiming
        8
    abcbuzhiming  
    OP
       3 天前
    @PolarisY 非常感谢给出最佳实践方案
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   941 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 19:18 · PVG 03:18 · LAX 11:18 · JFK 14:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.