BOM 介绍
BOM 是 Bill of Material 的简写,表示物料清单。BOM 使我们在使用 Maven 或 Gradle 构建项目时对于依赖版本的统一变得更加规范,升级依赖版本更容易。
比如我们使用 SpringBoot 和 SpringCloud 做项目时,可以使用他们发布的 BOM
- spring-boot-dependencies
- spring-cloud-dependencies
使用 Gradle 发布 BOM
在公司的大型项目中,可能对于依赖的版本需要有一个统一的管理,确保所有的项目的依赖都是一致的。
当需要升级某个依赖版本时,只需要更改 BOM 项目的版本并给发布一个新版本的 BOM 项目,然后在其他项目中引入这个新版本的 BOM 即可。
既然 BOM 这么便利,Gradle 没有理由不提供一个发布 BOM 的功能,Gradle 中的这个功能由插件 java-platform
实现。
官网关于插件的使用方式:https://docs.gradle.org/7.6.2/userguide/java_platform_plugin.html
建立 Gradle 项目的过程就省略了,可以看我其他的文章,此处假定已建立好一个项目,名字叫做:test-bom。
修改项目目录下的 build.gradle,使用以下代码引入插件:
plugins {id "java-platform"
}
很简单,引入这个插件之后只需要在 dependencies 下面的 constraints 中使用 api 方法引入任意喜欢的版本的依赖即可:
dependencies {constraints {// 比如此处我引入了 commons-lang3 的 jarapi("org.apache.commons:commons-lang3:3.12.0")// 其他的直接向下添加即可}
}
此处多出来一层 constraints。如果没有 constraints 的话,引用此 BOM 的项目,会自动引入
org.apache.commons:commons-lang3:3.12.0
,即使没有使用implementation
方法引入,这里涉及到 api 方法的其他方面,详见:Gradle几种引入依赖的方式介绍。
到这里这个 BOM 项目就好了。但是还有一个问题,我这个 BOM 如何给别人使用?和其他基础 库一样使用 maven-publish
插件。
首先引入 maven-publish 插件:
plugins {id "maven-publish"
}
接着定义 publish 的内容:
publishing {publications {testPlatform(MavenPublication) {from components.javaPlatform}}repositories {maven {url = "远程仓库地址"// 如果远程仓库是 https 的则不需要下面这句话,http 的需要// allowInsecureProtocol truecredentials {username = '远程仓库用户'password = '远程仓库密码'}}}
}
因为 jar 都是需要 groupId 和 artifactId 和版本的,而 artifactId 在 settings.gradle 中由 rootProject.name 定义,所以还需要在 build.gradle 中定义 groupId 和 version:
group = "com.test"
version = "1.0.0"
到目前为止,完整的 build.gradle 文件内容如下:
plugins {id "java-platform"id "maven-publish"
}group = "com.test"
version = "1.0.0"dependencies {constraints {// 比如此处我引入了 commons-lang3 的 jarapi("org.apache.commons:commons-lang3:3.12.0")// 其他的直接向下添加即可}
}publishing {publications {testPlatform(MavenPublication) {from components.javaPlatform}}repositories {maven {url = "远程仓库地址"// 如果远程仓库是 https 的则不需要下面这句话,http 的需要// allowInsecureProtocol truecredentials {username = '远程仓库用户'password = '远程仓库密码'}}}
}
在项目根目录下执行:
# Windows 使用 gradlew.bat 文件
./gradlew clean publishToMavenLocal
之后查看 $M2_HOME/repository/com/test/test-bom/1.0.0
,有两个文件就表示成功了:
使用发布的 BOM
使用 BOM 有两种方式,Gradle 自带的 platform 方法,和 SpringBoot 的插件,叫做 io.spring.dependency-management
。这两种方式看个人喜好使用。
Gradle API
api platform("com.test:test-bom:1.0.0")
Springboot 插件
插件稍微复杂些,先引入插件:
buildscripts {repositories {mavenCentral()}dependencies {// 非官方插件,需要引入 SpringBoot 插件库classpath("org.springframework.boot:spring-boot-gradle-plugin:2.7.18")}
}apply plugin: "java"
apply plugin: "io.spring.dependency-management"
然后在 dependencyManagement 引入 BOM 即可:
dependencyManagement {imports {mavenBom "com.test:test-bom:1.0.0"}
}
通过上面两种方式之一引入 BOM 之后,引入BOM 中存在的依赖就不用添加 version 了,如:
// 会自动引入 3.12.0 版本
implementation("org.apache.commons:commons-lang3")
到这里基本功能介绍完了。
那么问题来了,我如果在一个 SpringBoot 项目中使用了 SpringBoot 的依赖和我自定义的依赖,我还要写多个引入吗?
buildscripts dependencies 里面用 classpath 声明的第三方插件仓库也要自己指定版本吗?
buildscripts {dependencies {classpath("org.springframework.boot:spring-boot-gradle-plugin:2.7.18")}
}imports {mavenBom "springboot 的"mavenBom "springcloud 的"mavenBom "我自己的"
}
太难受了,我就想引入我自己的 BOM,并同时可以直接使用 SpringBoot 和 SpringCloud 的 BOM,这个可以搞。
改造 BOM 项目,添加:
javaPlatform {allowDependencies()
}dependencies {constraints {// xxx// 支持 classpath的api("org.springframework.boot:spring-boot-gradle-plugin:2.7.18")}api platform("org.springframework.boot:spring-boot-dependencies:2.7.18")api platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.8")
}
必须注意:不要写到 constraints 里面。
这样重新 publishToMavenLocal 就行了。
打包完成后,buildscripts 的引入方式需要修改一下:
buildscripts {dependencies {classpath platform("com.test:test-bom:1.0.0")classpath("org.springframework.boot:spring-boot-gradle-plugin")}
}
到这里,一个 BOM 支配所有依赖版本的项目就完成了,再也不怕依赖升级和维护了。
最后贴一下 BOM 和使用 BOM 的 build.gradle 的完整内容:
// bom build.gradle
plugins {id "java-platform"id "maven-publish"
}group = "com.test"
version = "1.0.0"javaPlatform {allowDependencies()
}dependencies {constraints {// 比如此处我引入了 commons-lang3 的 jarapi("org.apache.commons:commons-lang3:3.12.0")// 其他的直接向下添加即可// 支持 classpath的api("org.springframework.boot:spring-boot-gradle-plugin:2.7.18")}api platform("org.springframework.boot:spring-boot-dependencies:2.7.18")api platform("org.springframework.cloud:spring-cloud-dependencies:2021.0.8")}publishing {publications {testPlatform(MavenPublication) {from components.javaPlatform}}repositories {maven {url = "远程仓库地址"// 如果远程仓库是 https 的则不需要下面这句话,http 的需要// allowInsecureProtocol truecredentials {username = '远程仓库用户'password = '远程仓库密码'}}}
}
// 使用 BOM 的 build.gradle
buildscript {repositories {mavenCentral()}dependencies {classpath platform("com.test:test-bom:1.0.0")classpath("org.springframework.boot:spring-boot-gradle-plugin")}
}apply plugin: "java"
apply plugin: "org.springframework.boot"group = "com.test.web"
version = "1.0"sourceCompatibility = JavaVersion.VERSION_18
targetCompatibility = JavaVersion.VERSION_18repositories {mavenCentral()
}dependencies {implementation platform("com.test:test-bom:1.0.0")// spring bootimplementation("org.springframework.boot:spring-boot-starter-web")
}