为 Gradle 提供更好的依赖管理

工程 | Andy Wilkinson | 2015年2月23日 | ...

Maven 的依赖管理包含物料清单 (bom) 的概念。bom 是一种特殊的 pom,用于控制项目依赖项的版本,并提供一个中心位置来定义和更新这些版本。

包括 Spring Framework、Spring Cloud、Spring Boot 和 Spring IO Platform 在内的许多 Spring 项目都提供了 bom,以便 Maven 用户更容易使用。遗憾的是,如果你使用的是 Gradle,事情就没有那么容易了。

Gradle 中的依赖管理

Gradle 的依赖管理使用一个 ResolutionStrategy 来控制项目的依赖版本。这提供了很大的能力和灵活性,但没有提供一种重用 Maven bom 中已声明的依赖管理的方法。因此,你必须手动进行配置。根据 bom 的不同,这很容易导致你的 build.gradle 脚本中增加数十行代码,仅仅是为了重用一些现有配置。

在 Gradle 中重用 bom

Gradle 的主要优势之一是可以通过使用插件轻松扩展和定制其行为。我们利用了这一点,并为 Gradle 编写了一个依赖管理插件。它兼容 Gradle 1.x 和 2.x。这个插件允许你用几行代码使用 Maven bom 来控制构建的依赖项。第一步是应用插件

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath "io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE"
  }
}

apply plugin: "io.spring.dependency-management"

应用插件后,你可以使用它导入 Maven bom

dependencyManagement {
  imports {
    mavenBom 'io.spring.platform:platform-bom:1.1.1.RELEASE'
  }
}

有了这个配置,你就可以声明对 bom 中任何依赖项的依赖,而无需指定版本

dependencies {
    compile 'org.springframework:spring-core'
}

导入的 bom 将控制依赖项的版本。如果传递性依赖项在 bom 中列出,它也将控制其版本。

Gradle 中的排除

Gradle 可以从 Maven 仓库检索依赖项,并使用 Maven pom 文件中的元数据进行操作。然而,它并非遵守 Maven 的规则,而是对元数据应用了自己微妙不同的语义。其中一个可能导致问题的地方是传递性依赖项的排除。一个简单的例子可以最好地说明这一点。

想象一个模块依赖于几个 Spring Framework 模块,spring-corespring-beans,并且使用 SLF4J 而不是 Commons Logging。其 pom 中的依赖项可能看起来像这样

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.1.4.RELEASE</version>
  <exclusions>
    <exclusion>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>4.1.4.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
  <version>1.7.10</version>
</dependency>

如果一个 Maven 构建依赖于这个模块,它的依赖树将看起来像这样

\- com.example:my-library:jar:0.0.1-SNAPSHOT:compile
   +- org.springframework:spring-core:jar:4.1.4.RELEASE:compile
   +- org.springframework:spring-beans:jar:4.1.4.RELEASE:compile
   \- org.slf4j:jcl-over-slf4j:jar:1.7.10:compile
      \- org.slf4j:slf4j-api:jar:1.7.10:compile

commons-logging 没有被列出,因为唯一依赖它的模块是 spring-core,并且它已经被排除。

等效的 Gradle 构建的依赖树看起来像这样

\--- com.example:my-library:0.0.1-SNAPSHOT
     +--- org.springframework:spring-core:4.1.4.RELEASE
     |    \--- commons-logging:commons-logging:1.2
     +--- org.springframework:spring-beans:4.1.4.RELEASE
     |    \--- org.springframework:spring-core:4.1.4.RELEASE (*)
     \--- org.slf4j:jcl-over-slf4j:1.7.10
          \--- org.slf4j:slf4j-api:1.7.10

尽管进行了排除,这次 commons-logging 仍然被列出。这可能会有问题,因为它会使你的类路径充斥着本不应该存在的依赖项。你可以通过在 Gradle 构建中手动配置所需的排除来解决此问题,但首先你必须知道应该排除哪些依赖项,然后你必须经历繁琐且容易出错的配置过程。

遵守 pom 的排除规则

依赖管理插件改变了 Gradle 对 pom 排除规则的处理方式,使其行为与 Maven 中一致。将该插件应用于示例项目后,它不再引入 commons-logging

\--- com.example:my-library:0.0.1-SNAPSHOT
     +--- org.springframework:spring-core:4.1.4.RELEASE
     +--- org.springframework:spring-beans:4.1.4.RELEASE
     |    \--- org.springframework:spring-core:4.1.4.RELEASE
     \--- org.slf4j:jcl-over-slf4j:1.7.10
          \--- org.slf4j:slf4j-api:1.7.10

与 Spring Boot 一起使用插件

此插件与 Spring Boot 的 Gradle 插件有一些相似之处。例如,Spring Boot 插件也允许声明不带版本的依赖项,但它不影响传递性依赖项,也不遵守 Maven 的排除规则。

在即将发布的 Spring Boot 1.3 中,我们移除了 Boot 自己的依赖管理,转而开始使用依赖管理插件。对于使用早期版本 Spring Boot 的用户,这两个插件可以很好地共存,你可以配置依赖管理插件来使用 Spring Boot 的 starter bom

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath "io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE"
    classpath "org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE"
  }
}

apply plugin: "io.spring.dependency-management"
apply plugin: "spring-boot"

repositories {
  jcenter()
}

dependencyManagement {
  imports {
    mavenBom 'org.springframework.boot:spring-boot-starter-parent:1.2.1.RELEASE'
  }
}

dependencies {
  compile "org.springframework.boot:spring-boot-starter-web"
}

了解更多

除了上述功能外,该插件还支持使用 bom 的属性(包括覆盖它们并在你的 Gradle 构建中使用它们),自动在 Gradle 生成的 pom 文件中包含依赖管理元数据等等。请查看 README 获取更多详细信息。

该插件采用 Apache 许可,并在 GitHub 上可用。GitHub 也用于问题跟踪。功能建议、拉取请求和错误报告随时欢迎。

获取 Spring 新闻通讯

订阅 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,为你的进步加速。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区即将举行的所有活动。

查看全部