Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BOM should be declared in dependencyManagement for import #1561

Closed
JasonMing opened this issue May 6, 2021 · 28 comments
Closed

BOM should be declared in dependencyManagement for import #1561

JasonMing opened this issue May 6, 2021 · 28 comments

Comments

@JasonMing
Copy link

Currently, hutool-bom cannot be imported because the modules are declared in dependencies block.
However, "bom" means user can import this pom file to manage versions instead of bring transitive dependencies.

@looly
Copy link
Member

looly commented May 8, 2021

Hutool的bom采用”排除法“,即不需要哪个去掉哪个,而不是需要哪个加哪个。

如果需要后者需求,单独引入hutool-XXX即可。

@looly looly closed this as completed May 8, 2021
@looly looly added the question label May 8, 2021
@JasonMing
Copy link
Author

JasonMing commented May 8, 2021

不提供bom那怎么做版本对齐?
考虑如下情况:

project -> A -> hutool-aop@4.6.9 -> hutool-core@4.6.9
        -> hutool-db@5.6.3 -> hutool-core@5.6.3

此时hutool-*的包在classpath上版本可能是不对齐的,maven诡异的依赖解释逻辑,不可能期望每个使用者去理解这种菱形依赖的解释规则,并且hutool包之内也有依赖性,这样的情况没有一个可以import的bom来对齐版本难道需要使用者一个一个依赖去找然后exclude吗?

@looly
Copy link
Member

looly commented May 8, 2021

暂时只能这样,关于标准的bom操作,我在考虑如何加入。

@JasonMing
Copy link
Author

按道理bom的定义只需要提供一个带有所有模块的dependencyManagement的声明即可,还是有什么特别的考量吗?

我提这个issue就是团队里面因为二方库升级时候出现了很多版本不对齐的问题,现在只能我们自己list出所有的模块,非常麻烦。

@looly
Copy link
Member

looly commented May 8, 2021

其实最简单的方法就是使用hutool-all比较简单。

@JasonMing
Copy link
Author

JasonMing commented May 11, 2021

如果是同一个项目控制还好,多个项目带上依赖包根本就不可控,jvm又不像.net clr那样有application domain机制,hutool-all还是会和其它hutool-*的类冲突。

@looly
Copy link
Member

looly commented May 11, 2021

确实有这个问题。bom这块我看如何修改。

@scruel
Copy link
Contributor

scruel commented Oct 18, 2021

确实有这个问题。bom这块我看如何修改。

建议:
hutool-all 支持排除,hutool-bom 遵循业内约定。

@looly
Copy link
Member

looly commented Oct 18, 2021

hutool-all是统一打包方式,bom模块现在升级擅自修改逻辑已有项目肯定出问题,所以大版本更新前保持现在的方式。

@looly
Copy link
Member

looly commented Oct 18, 2021

hutool-all是统一打包方式,bom模块现在升级擅自修改逻辑已有项目肯定出问题,所以大版本更新前保持现在的方式。

历史原因可挺真恼人的。。。

对的,其实问题在于早期对这个包管理理解不够透彻导致规划没有做好,包括现在Hutool中很多工具类所在包都不合理,都是历史版本原因造成的。

计划在6.x.x做一次大重构,来解决这些不合理问题。

@scruel
Copy link
Contributor

scruel commented Oct 18, 2021

hutool-all是统一打包方式,bom模块现在升级擅自修改逻辑已有项目肯定出问题,所以大版本更新前保持现在的方式。

历史原因可挺真恼人的。。不过有一说一,工具包一般不会升级。
相关问题从 19 年就一直有人在开 issue,建议尽早一劳永逸解决,或者大版本(x 版本)更新的时候写个升级 wiki。

@scruel
Copy link
Contributor

scruel commented Oct 18, 2021

hutool-all是统一打包方式,bom模块现在升级擅自修改逻辑已有项目肯定出问题,所以大版本更新前保持现在的方式。

历史原因可挺真恼人的。。。

对的,其实问题在于早期对这个包管理理解不够透彻导致规划没有做好,包括现在Hutool中很多工具类所在包都不合理,都是历史版本原因造成的。

计划在6.x.x做一次大重构,来解决这些不合理问题。

好的了解,期待重构版本。

@looly
Copy link
Member

looly commented Oct 18, 2021

哈哈,你知道一些方法我从5.0.x就标记废弃,5.7.x删除这些方法,用户升级后就开始国粹了么。

大部分用户是不想花精力来解决升级导致的兼容问题的,这也是为何jdk6依旧“流行”的原因。

@scruel
Copy link
Contributor

scruel commented Oct 20, 2021

哈哈,你知道一些方法我从5.0.x就标记废弃,5.7.x删除这些方法,用户升级后就开始国粹了么。

大部分用户是不想花精力来解决升级导致的兼容问题的,这也是为何jdk6依旧“流行”的原因。

不论如何,改变总是难的,这块可以参考下其他项目,比如 netty-bom 等的设计,bom 也是会包含 all 模块的版本的。

@looly
Copy link
Member

looly commented Oct 20, 2021

@scruel 感谢意见,这些改变都会留在6.x中来变更。

@JasonMing
Copy link
Author

JasonMing commented Oct 20, 2021

@looly
其实,hutool-bom现在纯粹是个pom,也没有import相关的能力。
在目标项目当作bom使用 import 的时候,只会读取 dependencyManagement 的配置;
在目标项目当作普通依赖直接引用的时候,只会读取 dependencies 的配置。

现在就加上 dependencyManagement 声明并不会对目标项目产生任何额外的副作用。

@looly
Copy link
Member

looly commented Oct 20, 2021

@JasonMing 意思两个可以同时存在?稍后我做下尝试。

@JasonMing
Copy link
Author

@JasonMing 意思两个可以同时存在?稍后我做下尝试。

是的,举个例子:

<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-bom</artifactId>
        <version>5.7.14</version>
        <type>pom</type> <!-- bom组件没有对应jar必须显式指定类型 -->
    </dependency>
</dependencies>

这个配置会传递依赖hutool-bom内所有dependencies的内容,当前hutool-bom内的dependencies全部设置了version,就意味着在maven resolve的时候hutool-bom内就算存在dependencyManagement也不会产生任何作用。

同理,在如下使用场景中:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-bom</artifactId>
            <version>5.7.14</version>
            <type>pom</type>
            <scope>import</scope> <!-- 注意这里是import -->
        </dependency>
    </dependencies>
</dependencyManagement>

使用import的方式,只会引入hutool-bom内的dependencyManagement的配置,其它配置在这个引用方式下完全不起作用。

@looly
Copy link
Member

looly commented Oct 20, 2021

@JasonMing 太棒了!经过测试非常好用,这样就即解决了兼容问题,又加入了真正的bom功能!十分感谢,学习了。

5.7.15会修改hutool-bom的pom.xml为这种格式,支持两种引入方式!

@scruel
Copy link
Contributor

scruel commented Oct 21, 2021

@looly
但是如何用户项目是把 hutool-bom 直接为了排除部分 hutool-all 模块,作直接依赖使用的话,变更为 dependencyManagement 会导致用户项目不再引入需要的其他依赖。

@JasonMing
Copy link
Author

但是如何用户项目是把 hutool-bom 直接为了排除部分 hutool-all 模块,作直接依赖使用的话,变更为 dependencyManagement 会导致用户项目不再引入需要的其他依赖。

@scruel 不要搞错「引入」和「定义」哦。
<dependencyManagement> 里面是定义了版本而已,用户如果不主动import原来是什么的还是什么。
现在是追加 <dependencyManagement> 定义而不是换掉,原来的用户依赖 hutool-bom 通过传递依赖把相关模块引入的机制并没有被改变。
hutool-all 其实是一个大的集成包,同个版本中,里面的类都和其它小包里面的是一样的。

@JasonMing
Copy link
Author

@JasonMing 太棒了!经过测试非常好用,这样就即解决了兼容问题,又加入了真正的bom功能!十分感谢,学习了。

5.7.15会修改hutool-bom的pom.xml为这种格式,支持两种引入方式!

@looly 提个建议,6.0开始可以使用gradle作为构建脚本,maven的方式真心不够灵活,各种本地构建配置对pom.xml的污染很严重。

@scruel
Copy link
Contributor

scruel commented Oct 21, 2021

@JasonMing
确实以为是替换了,不好意思没有看清楚,因为之前测试的是替换:

如果有用户项目在 pom 中使用如下代码,也可「引入」依赖(非 dependencyManagement 下「定义」):

<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-bom</artifactId>
        <version>${hutool.version}</version>
        <type>pom</type> <!-- 加不加这句都能跑,区别只有是否告警 -->
    </dependency>
</dependencies>

这个效果和下面代码的效果,可以视为是一致的:

<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>${hutool.version}</version>
    </dependency>
</dependencies>

而如果 hutool-bom 直接修改增加 dependencyManagement ,会导致这样使用的部分用户项目中的不再有 hutool 的相关依赖。
而如下的使用方式(排除模式),也是 @looly 之前在 Gitee 上所推荐的用法:

<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-bom</artifactId>
        <version>${hutool.version}</version>
        <type>pom</type> <!-- 加不加这句都能跑,区别只有是否告警  -->
        <exclusions>
            <exclusion>
                    <groupId>cn.hutool</groupId>
                    <artifactId>hutool-aop</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

可以自己测试一下。

@scruel
Copy link
Contributor

scruel commented Oct 21, 2021

@JasonMing 太棒了!经过测试非常好用,这样就即解决了兼容问题,又加入了真正的bom功能!十分感谢,学习了。
5.7.15会修改hutool-bom的pom.xml为这种格式,支持两种引入方式!

@looly 提个建议,6.0开始可以使用gradle作为构建脚本,maven的方式真心不够灵活,各种本地构建配置对pom.xml的污染很严重。

Gradle 确实更加灵活,包括安卓和 IDEA Plugin 的开发都推荐使用 Gradle 作为构建工具。不过既然都是工具,能用且够用就行,如果时间上不够充裕的话。

@looly
Copy link
Member

looly commented Oct 21, 2021

考虑过Gradle,不过对这个东西不熟悉,迁移看时间吧。

@JasonMing
Copy link
Author

JasonMing commented Nov 27, 2021

@scruel 有几点是不对的

        <type>pom</type> <!-- 加不加这句都能跑,区别只有是否告警 -->

因为 hutool-bom 没发 jar 包,实际上这个依赖的artifact是不存在的,但是因为解释依赖的时候下载了pom,所以碰巧能读取到对应的传递依赖,说白了这是个UB,不能因为能用就去用。


这个效果和下面代码的效果,可以视为是一致的:

这是不对的,通过引入 hutool-bom,所有artifact是通过传递依赖引入的,如果没有 dependencyManagement 管控,按照maven的 nearest wins 原则,如果有其他依赖里面有传递依赖,那解释结果是不稳定的。
但是如果通过 hutool-all 引入,因为只有一个GAV,起码能保证hutool-all里面的类是一致的。
但其实现在 hutool-* 的引入模式还是存在缺陷,hutool-all 如果和 hutool-* 同时存在的话,可能会因为类加载顺序而出现某些包里面的类和预想版本不对齐的情况。

@JasonMing
Copy link
Author

@JasonMing 事实上这个加不加 bom 只是为了告诉你,并不是没有区别,也没有为了能用就去用,因为这个本身就不该按 hutool 的方式来做排除。 实际上引入 bom 也有很多问题,比如无法支持到 exclusive 等等(对 bom 定义的部分 exclusive,避免要覆盖定义一堆三方库),最后还是需要按最近依赖去定义统一的 bom 下版本(公司自己的),而不是依靠三方项目给你的定义,做的好点就全部 shade 掉,完美解决问题但是会让 jar 包变大。 总结这里只是为了回复你所谓的定义混淆、直接替换后不会有问题等,并不是在说怎么使用的问题,您对我发出的几个回复可能都有所误解。

em...你的观点其实我并不太赞同。
首先,hutool作为一个整体却有多个组件,还是应该出一个完整的Bill-of-Materials的,起码作为一个官方提供的清单,至于用不用这是使用者的问题。
其次【比如无法支持到 exclusive 等等】,这个本来就是maven自身的问题,没法全局排包,这种有私库的基本都是发个空包然后用dependencyMangement强制定义某个依赖的版本到空包版本实现的,和hutool自身是否发bom并不矛盾。
最后一个,应用项目用shade方式感觉就是找自己不愉快的,这个本来就是java的锅,没有一个方便运行域隔离机制(类似C#的),依赖冲突一般体现在API兼容上,对齐下依赖版本就好的事情就不要shade了,而对齐依赖版本正是需要官方给我们提供bom。

@scruel
Copy link
Contributor

scruel commented Nov 29, 2021

纠正了上面的回复,错误理解了【追加】,对增加的沟通成本表示歉意。

另外你说的几个点上还可以讨论下:

实际上这个依赖的artifact是不存在的,但是因为解释依赖的时候下载了pom,所以碰巧能读取到对应的传递依赖,说白了这是个UB,不能因为能用就去用。
至于用不用这是使用者的问题。

这个不算是一个 UB,bom 是 maven 的提供的一个特性,如果这算能用就用的话,那这个特性感觉就没有存在的必要了。用不用方面只是点出了几个实际问题,这里说的当然是要支持的,不然也没必要通过这个 issue 来讨论了。

没有 dependencyManagement 管控,那解释结果是不稳定的。
比如无法支持到 exclusive 等等,这个本来就是maven自身的问题

实际上即便有了 dependencyManagement 管控,不注意的话也会出现不稳定情况的,比如包含同一三方库的两个 bom 的声明顺序。maven 自身的问题确实棘手,不过对于 hutool 来说的话,没有三方依赖的情形下是比较容易解决的。
运行域隔离机制主要是设计的问题吧,不过还是可以通过重写类加载器这种”不方便的方式“来实现的?

应用项目用shade方式感觉就是找自己不愉快的,对齐下依赖版本就好的事情就不要shade了,而对齐依赖版本正是需要官方给我们提供bom

"对齐下依赖版本就好的事情就不要shade了",这个没问题,但有些情况是没办法才会去 shade 来解决冲突,上面也提到过了,即便提供了 bom 也不是完全就能确保解决问题了的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants