聊一聊BOM:多模块的依赖版本管理

大家好,我是G探险者!

最近项目上在整理各个组件的POM依赖,试图通过一个父级POM来管理整个项目上使用到的各种开源的,和自研的依赖。目的是为了规范使用我们框架的应用,不私自在自身项目里面乱定版本,导致各种版本冲突不兼容的问题。

在这个整理的过程中我们也遇到了一些坑,比如有的组件里面使用了netty,中的某个依赖包,另外的组件使用到了netty的另外的依赖包,那么我们在统一管理netty这些依赖的时候,维护了的netty的依赖版本就有点五花八门,导致应用在使用我们的这个父级POM时,出现了一些奇奇怪怪的版本不兼容问题。

于是引入了BOM这个概念,今天我们就来聊一聊BOM是如何进行多模块项目的依赖管理的。

BOM 的由来

BOM(Bill of Materials,材料清单)最早的概念来源于制造业,用于描述构建产品所需的组件清单。在软件开发领域,BOM 被用于列出某个项目或工具的所有依赖及其版本信息,确保这些依赖模块能够兼容协作。

在 Java 的依赖管理工具中,如 Maven 和 Gradle,BOM 解决了模块化项目中版本管理的复杂性问题。许多大型项目(如 Spring Framework、Jetty、netty,springcloud)随着功能的扩展和模块化设计,逐步拆分为多个子模块。每个子模块可能独立演进,但它们之间需要确保版本一致和兼容性。于是引入了 BOM 来统一管理这些模块的版本。

BOM 的作用

  1. 统一版本管理

    • BOM 是一个特殊的 Maven POM 文件(pom.xml),它列出了多个相关模块及其推荐的版本。
    • 使用 BOM 后,开发者无需在每个依赖声明中显式指定版本,避免版本冲突和错误。

    示例

    xml 复制代码
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-server</artifactId>
                <version>11.0.15</version>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-servlet</artifactId>
                <version>11.0.15</version>
            </dependency>
            <!-- 其他模块省略 -->
        </dependencies>
    </dependencyManagement>
  2. 避免版本冲突

    • 在大型项目中,不同模块可能依赖同一个库的不同版本。BOM 确保所有模块使用相同版本,从而避免潜在冲突。
  3. 简化依赖声明

    • 在 Maven 中,通过引入 BOM 后,子模块的版本可以被自动解析。

    示例

    xml 复制代码
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-bom</artifactId>
                <version>11.0.15</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    子模块中使用依赖时不再需要显式声明版本:

    xml 复制代码
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
        </dependency>
    </dependencies>
  4. 提高维护效率

    • BOM 集中管理所有模块的版本,可以在 BOM 文件中一次性升级所有相关依赖版本,降低手动管理的复杂性。
  5. 明确兼容性

    • BOM 通常由项目开发团队发布,确保其中列出的模块版本是经过测试、互相兼容的。

BOM 的使用场景

  1. 多模块项目

    • 适用于一个大项目分拆成多个模块(如 Jetty),开发团队可以提供 BOM 供用户引用,避免用户在不同模块间手动匹配版本。
  2. 集成框架

    • 像 Spring Boot 提供了自己的 BOM,管理 Spring 框架及常用第三方库的版本。开发者只需选择一个 BOM 文件即可。

    Spring Boot 示例

    xml 复制代码
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>3.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
  3. 企业级项目

    • 企业内部开发的框架或工具库,可以用 BOM 提供统一的依赖管理,提升团队协作效率。

家族式依赖和非家族式依赖

非家族式依赖顾名思义,就是它没有过多的相关联的依赖包,在维护时只需要一个依赖即可,比如mysql的驱动包

所谓家族式依赖就是指的是,像jetty,netty,springcloud等这样的依赖,比如jetty家族:

依赖包 功能描述 依赖模块
核心组件
jetty-util 提供通用工具库(线程池、集合工具、日志等)。 无直接依赖
jetty-io 异步 IO 操作支持,底层 IO 模块。 jetty-util
jetty-http 处理 HTTP 协议解析和生成。 jetty-io
jetty-server Jetty 核心服务器模块,处理 HTTP 请求与响应。 jetty-http, jetty-io, jetty-util
jetty-servlet 提供 Servlet 容器支持。 jetty-server
高级功能模块
jetty-security 提供认证和授权功能。 jetty-server, jetty-util
jetty-proxy 实现反向代理功能。 jetty-server
jetty-websocket-server WebSocket 服务端支持。 jetty-server, jetty-websocket-common
jetty-websocket-client WebSocket 客户端支持。 jetty-client, jetty-websocket-common
集成模块
jetty-servlets 提供扩展的 servlet 功能和过滤器支持。 jetty-servlet
jetty-jndi 提供 JNDI 支持。 jetty-server, jetty-util
jetty-alpn 支持 HTTP/2 中的 ALPN 协议。 jetty-server, jetty-io
测试与开发工具
jetty-annotations 支持基于注解的配置(如 Servlet 3.0 注解)。 jetty-servlet
jetty-test-helper 提供测试工具,便于编写测试用例。 jetty-server
jetty-distribution 提供完整的 Jetty 服务器分发包,适合快速运行与调试。 包含多个核心模块

netty家族:

模块 artifactId 功能描述
Netty BOM netty-bom 包含所有 Netty 相关模块的版本定义,用于依赖版本管理
Netty Common netty-common 提供 Netty 的常用工具类,例如线程池、日志、时间处理等
Netty Transport netty-transport 提供高性能的网络传输功能,包括 NIO、EPOLL、KQueue 等支持
Netty Codec netty-codec 提供对各种协议的编码解码支持(如 HTTP、HTTP/2、WebSocket 等)
Netty Handler netty-handler 提供常见的 I/O 事件处理程序(例如 HTTP 请求处理、SSL/TLS 加密、WebSocket 等)
Netty Buffer netty-buffer 提供 Netty 的内存缓冲区 API
Netty Codecs HTTP netty-codec-http 提供 HTTP 协议的编码解码器支持
Netty Codecs SSL netty-codec-ssl 提供 SSL/TLS 编码解码支持
Netty Resolver netty-resolver 提供 DNS 解析、服务发现等功能
Netty Handler Proxy netty-handler-proxy 提供代理协议(如 HTTP 代理)的支持
Netty Handler SSL netty-handler-ssl 提供 SSL/TLS 协议的处理程序
Netty Transport Epoll netty-transport-epoll 支持基于 EPOLL 的传输机制(Linux 环境)
Netty Transport KQueue netty-transport-kqueue 支持基于 KQueue 的传输机制(macOS 环境)

这些家族式的依赖如果维护到一个父级pom里,应该如何更好的维护到一个POM里面呢,这就要发挥BOM的作用了。

以下我提供一个示例:

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>parent-pom</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <properties>
        <!-- 家族依赖的版本管理 -->
        <spring.boot.version>2.6.3</spring.boot.version>
        <spring.cloud.version>2021.0.0</spring.cloud.version>
        <netty.version>4.1.72.Final</netty.version>
        <jetty.version>11.0.1</jetty.version>
        <hutool.version>5.8.5</hutool.version>

        <!-- 非家族依赖的版本管理 -->
        <mysql.version>8.0.27</mysql.version>
        <commons.lang.version>3.12.0</commons.lang.version>
        <log4j.version>2.17.0</log4j.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- 引入 Spring Boot BOM -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- 引入 Spring Cloud BOM -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- 引入 Netty BOM -->
            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-bom</artifactId>
                <version>${netty.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- 引入 Jetty BOM -->
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-bom</artifactId>
                <version>${jetty.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- 其他家族性质依赖管理 -->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>${hutool.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>

            <!-- 非家族依赖 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>${commons.lang.version}</version>
            </dependency>

            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
  1. 非家族依赖的版本管理 :在 <dependencyManagement> 中加入了 mysql-connector-javacommons-lang3log4j-api 这些非家族性质的依赖。这样可以确保所有模块使用一致的版本,无需每个子模块都指定版本。

  2. BOM 和常规依赖统一管理 :现在无论是家族依赖(如 Spring Boot、Spring Cloud 等),还是常规依赖(如 MySQL、Commons、Log4j 等),都在 dependencyManagement 中进行了版本管理。

  3. 集中版本管理 :所有的版本号都通过 ${property.name} 统一管理,保证了依赖的版本一致性,方便在不同模块间共享和更新版本。

以上这种方式不仅集中管理了所有依赖的版本,还确保了无论是家族性质的依赖,还是其他常规依赖,都能在一个地方进行统一的版本控制。

相关推荐
程序员岳焱4 小时前
Java 与 MySQL 性能优化:Java 实现百万数据分批次插入的最佳实践
后端·mysql·性能优化
麦兜*4 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
大只鹅5 小时前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
ai小鬼头5 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
IT_10245 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
bobz9656 小时前
动态规划
后端
stark张宇6 小时前
VMware 虚拟机装 Linux Centos 7.9 保姆级教程(附资源包)
linux·后端
亚力山大抵7 小时前
实验六-使用PyMySQL数据存储的Flask登录系统-实验七-集成Flask-SocketIO的实时通信系统
后端·python·flask
超级小忍7 小时前
Spring Boot 中常用的工具类库及其使用示例(完整版)
spring boot·后端
CHENWENFEIc8 小时前
SpringBoot论坛系统安全测试实战报告
spring boot·后端·程序人生·spring·系统安全·安全测试