依赖约束 的功能类似于依赖项,但关键区别在于它们本身不引入依赖项。相反,约束定义了版本要求,这些要求会影响依赖项通过其他方式引入项目时的解析过程。

尽管约束默认不是严格版本,但如果需要,可以指定严格版本约束。一旦包含依赖项,约束指定的版本会参与冲突解决,就像它被声明为直接依赖项一样。

在开发单项目库时,约束 可以直接与直接依赖项一起声明。然而,在开发多项目库和应用程序时,最好在平台中集中声明依赖项

build.gradle.kts
plugins {
    `java-platform`
}

dependencies {
    constraints {
        // Platform declares some versions of libraries used in subprojects
        api("commons-httpclient:commons-httpclient:3.1")
        api("org.apache.commons:commons-lang3:3.8.1")
    }
}
build.gradle
plugins {
    id 'java-platform'
}

dependencies {
    constraints {
        // Platform declares some versions of libraries used in subprojects
        api 'commons-httpclient:commons-httpclient:3.1'
        api 'org.apache.commons:commons-lang3:3.8.1'
    }
}

通常,依赖项分为**直接依赖项**或**传递依赖项**

  • 直接依赖项 是指在组件的构建或元数据中明确指定的依赖项。

  • 传递依赖项 不是直接指定的;它们作为直接依赖项的依赖项自动被引入。

一个组件可能需要直接依赖项和传递依赖项才能编译或运行。

与直接依赖项一起声明约束

依赖约束 允许您为特定的依赖项定义版本或版本范围,*只要在解析过程中遇到该依赖项*。

这是跨多个配置或项目管理组件版本的首选方法。

当 Gradle 解析模块版本时,它会考虑所有相关因素,包括丰富版本、传递依赖项以及该模块的依赖约束。将选择满足所有条件的最高版本。如果不存在这样的版本,Gradle 将会因错误而失败,并详细说明冲突的声明。

在这种情况下,您可以调整依赖项声明、依赖约束,或对传递依赖项进行必要的更改。

与依赖项声明一样,依赖约束也按配置划分范围,允许您有选择地将它们应用于构建的特定部分。

constraints{} 块用于 dependencies{} 块内声明这些约束

build.gradle.kts
plugins {
    `java-platform`
}

dependencies {
    constraints {
        api("commons-httpclient:commons-httpclient:3.1")
        runtime("org.postgresql:postgresql:42.2.5")
    }
}
build.gradle
plugins {
    id 'java-platform'
}

dependencies {
    constraints {
        api 'commons-httpclient:commons-httpclient:3.1'
        runtime 'org.postgresql:postgresql:42.2.5'
    }
}
  1. api("commons-httpclient:commons-httpclient:3.1"):

    • 这一行在 api 配置上创建了一个约束,断言如果 commons-httpclient 被扩展 api 配置的可解析配置解析时,其版本必须是 3.1 或更高。

    • 如果传递依赖项(依赖项的依赖项)或项目中的另一个模块引入了不同版本的 commons-httpclient,Gradle 将强制该依赖项解析到至少 3.1 版本。

    • 这个约束确保了库 commons-httpclient 在所有扩展 api 配置的配置中至少是 3.1 版本。

  2. runtime("org.postgresql:postgresql:42.2.5"):

    • 类似地,这一行在 runtime 配置上应用了一个约束,强制 org.postgresql:postgresql 必须解析到至少 42.2.5 版本。

    • 即使项目中的其他依赖项或模块试图引入不同版本的 postgresql,Gradle 也将选择 42.2.5 和其他声明版本中更高的那个。

    • 这确保了对 postgresql 的任何运行时依赖项在所有扩展 runtime 配置的可解析配置中都将解析到至少 42.2.5 版本。

添加传递依赖的约束

依赖管理问题经常源于传递依赖项。开发人员有时会错误地通过添加直接依赖项来解决这些问题,而不是使用约束来正确处理。

依赖约束 允许您控制传递依赖项的选择。

在下面的示例中,commons-codec:1.11 的版本约束仅在 commons-codec 作为传递依赖项引入时才适用,因为它没有直接声明为项目中的依赖项。如果 commons-codec 没有作为传递依赖项引入,则该约束无效

build.gradle.kts
dependencies {
    implementation("org.apache.httpcomponents:httpclient")
    constraints {
        implementation("org.apache.httpcomponents:httpclient:4.5.3") {
            because("previous versions have a bug impacting this application")
        }
        implementation("commons-codec:commons-codec:1.11") {
            because("version 1.9 pulled from httpclient has bugs affecting this application")
        }
    }
}
build.gradle
dependencies {
    implementation 'org.apache.httpcomponents:httpclient'
    constraints {
        implementation('org.apache.httpcomponents:httpclient:4.5.3') {
            because 'previous versions have a bug impacting this application'
        }
        implementation('commons-codec:commons-codec:1.11') {
            because 'version 1.9 pulled from httpclient has bugs affecting this application'
        }
    }
}

依赖约束还可以定义丰富版本约束并支持严格版本,允许您强制使用特定版本,即使该版本与传递依赖项的版本冲突(例如,如果需要降级)。

依赖约束仅在使用Gradle 模块元数据时才会发布。这意味着它们只有在使用 Gradle 发布和消费模块时才能获得完全支持。如果使用 Maven 或 Ivy 消费模块,则约束可能无法保留。

依赖约束是传递性的。如果 库 A 依赖于 库 B,并且 库 B 声明了对 模块 C 的约束,那么该约束将影响 库 A 依赖的 模块 C 的版本。

例如,如果 库 A 依赖于 模块 C 版本 2,但 库 B 声明了对 模块 C 版本 3 的约束,则 库 A 将解析到 模块 C 版本 3