BOM 减少版本冲突

在应用了Gradle构建工具,以及Maven仓库来管理版本依赖后,程序的构建、依赖问题已经得到了基本的解决。

但随着项目的不断发展,一个微服务的依赖可能会越来越多,出现版本冲突的问题。

举个版本冲突的例子:项目依赖的A的0.9版本,同时依赖了项目B,项目B又依赖了项目A的1.0版本。此时,项目会选择A的0.9还是1.0版本呢?

事实上,按照Maven的依赖规则,会选用最小的版本0.9。如果0.9和1.0是API兼容的,那么问题不大。如果1.0的API发生了”break change”,那么很遗憾,项目B中的代码会包错,更离谱的是,只有运行时才会发生问题。这类问题经常难以诊断,因此,我们应当尽量减少版本冲突的问题。

BOM(Bill Of Materials)就是为了解决这个问题而生的,它定义了一组依赖管理的项目并约定了对应的版本。其他项目可以直接引用BOM而不用设定对应版本,BOM会自动把缺失的版本补全。

在本书的微服务架构下,我们强烈建议定义公共库的BOM,以减少版本冲突的问题。

应用BOM需要两个步骤:

  1. 新建一个BOM的Maven项目
  2. 在项目中引用该BOM项目

新建一个BOM项目非常简单,只需要一个xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.coder4.lmsia</groupId>
  7. <artifactId>pom-parent</artifactId>
  8. <version>0.0.4</version>
  9. <packaging>pom</packaging>
  10. <properties>
  11. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  12. <java.version>1.8</java.version>
  13. </properties>
  14. <dependencyManagement>
  15. <dependencies>
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-dependencies</artifactId>
  19. <version>1.5.7.RELEASE</version>
  20. <type>pom</type>
  21. <scope>import</scope>
  22. </dependency>
  23. <dependency>
  24. <groupId>com.google.guava</groupId>
  25. <artifactId>guava</artifactId>
  26. <version>23.0</version>
  27. </dependency>
  28. <!-- lmsia start -->
  29. <dependency>
  30. <groupId>com.coder4.lmsia</groupId>
  31. <artifactId>redis</artifactId>
  32. <version>0.0.4</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>com.coder4.lmsia</groupId>
  36. <artifactId>cache</artifactId>
  37. <version>0.0.5</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>com.coder4.lmsia</groupId>
  41. <artifactId>rabbitmq</artifactId>
  42. <version>0.0.2</version>
  43. </dependency>
  44. <dependency>
  45. <groupId>com.coder4.lmsia</groupId>
  46. <artifactId>thrift-server</artifactId>
  47. <version>0.0.5</version>
  48. </dependency>
  49. <dependency>
  50. <groupId>com.coder4.lmsia</groupId>
  51. <artifactId>database</artifactId>
  52. <version>0.0.1</version>
  53. </dependency>
  54. <dependency>
  55. <groupId>com.h2database</groupId>
  56. <artifactId>h2</artifactId>
  57. <version>1.4.196</version>
  58. </dependency>
  59. <!-- lmsia end -->
  60. </dependencies>
  61. </dependencyManagement>
  62. <distributionManagement>
  63. <repository>
  64. <id>nexus_coder4</id>
  65. <url>http://192.168.99.100:8081/nexus/content/repositories/releases/</url>
  66. </repository>
  67. <snapshotRepository>
  68. <id>nexus_coder4</id>
  69. <url>http://192.168.99.100:8081/nexus/content/repositories/snapshots/</url>
  70. </snapshotRepository>
  71. </distributionManagement>
  72. </project>

解释下上面的代码:

  1. 这是一个pom,应用了若干包,并指定了他们的版本
  2. 底部指定了maven仓库的发布地址(如果你有多个不同的maven repo权限才需要设定)

然后看一下在gradle项目中如何引用bom:

build.gradle:

  1. plugins {
  2. id "io.spring.dependency-management" version "1.0.3.RELEASE"
  3. }
  4. apply plugin: 'java'
  5. apply plugin: 'application'
  6. repositories {
  7. maven {
  8. credentials {
  9. username "$mavenUser"
  10. password "$mavenPass"
  11. }
  12. url 'http://maven.coder4.com/nexus/content/groups/public'
  13. }
  14. }
  15. // import bom
  16. dependencyManagement {
  17. imports {
  18. mavenBom 'com.coder4.sbmvt:pom-parent:0.0.1'
  19. }
  20. }
  21. dependencies {
  22. // use bom version
  23. compile 'org.springframework.boot:spring-boot-starter-web'
  24. compile 'com.coder4.lmsia:redis'
  25. // Use JUnit test framework
  26. testCompile 'junit:junit:4.12'
  27. }
  28. // Define the main class for the application
  29. mainClassName = 'App'

如上所示,我们通过dependencyManagement插件引入了bom项目,而指定项目时只有group和project、没有版本,版本会自动使用bom中统一定义的。

对于微服务架构,我们可以将使用的数据库、RPC、消息队列、工具类等共用库的版本都放入BOM,以统一依赖的版本。