Java的世界里,几乎所有项目的包管理都是使用了Maven,或者在其之上演进的组件。大型项目比如有成百上千个工程,依赖的包比较多,如果没有统一的版本管理,很容易就失控了。
项目中pom.xml来管理依赖包,会遵循一个最短路径依赖。先看一个Case
<dependencies>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-spring</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>com.lihongkun.labs</groupId>
<artifactId>jmh</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
如上代码,项目中依赖了两个jar包,他们各自的依赖如下图
可以看到这两个包的依赖树如图,其中的gson包版本是不一致的。按照最短路径原则的化2.2.2版本的包它的路径是比较短的。所以选择了2.2.2版本。我们可以使用 mvn dependency:tree命令来看最后选择的依赖。
这种情况下,会导致应用无法启动。因为elasticjob的使用强依赖于2.6.1,而其中使用的功能在2.2.2不存在。解决这种版本冲突比较简单,直接使用更短的路径依赖去覆盖,即在本项目中显式指定依赖和版本。但是当项目比较多的时候,坏处就显而易见了。
BOM(Bill of Materials)是由Maven提供的功能,它通过定义一整套相互兼容的jar包版本集合,使用时只需要依赖该BOM文件,即可放心的使用需要的依赖jar包,且无需再指定版本号。BOM的维护方负责版本升级,并保证BOM中定义的jar包版本之间的兼容性。
典型的应用如 使用Spring框架时,直接引入其bom进行包依赖管理。在使用具体的包时则不需要再进行包版本的声明。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.3.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependencies>
既然有这样好处,那么我们在平时项目的管理中如何编写BOM。建议是整个部门或者大的项目由一个统一的BOM进行管理。
<groupId>com.lihongkun.labs</groupId>
<artifactId>bom</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<!--声明依赖和版本-->
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version>
</dependency>
<dependencies>
</dependencyManagement>
编写方式同平时进行包依赖引入的时候没什么差别。只是所有的依赖都是使用dependencyManagement这个标签包含起来。
<!--引入bom进行依赖管理-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.lihongkun.labs</groupId>
<artifactId>bom</artifactId>
<version>1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--声明本项目所需要的依赖-->
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<!--指定版本号进行覆盖-->
<version>1.2.66</version>
</dependency>
<dependencies>
使用了上述方式即可直接对其中声明的包进行统一的版本管理。如上述代码,fastjson在本项目中需要进行一个单独升级,那么可以直接指定版本号进行覆盖。框架虽然留下了这种灵活性,但是实际使用中最好是进行统一管理。
如果团队中经常出现包管理的问题,不妨使用以下BOM,会有意想不到的效果。