在 Gradle 中,如何在一个地方声明公共依赖项?

Posted

技术标签:

【中文标题】在 Gradle 中,如何在一个地方声明公共依赖项?【英文标题】:In Gradle, how do I declare common dependencies in a single place? 【发布时间】:2012-03-21 18:36:15 【问题描述】:

在 Maven 中有一个非常有用的功能,您可以在父 POM 的 <dependencyManagement> 部分定义依赖项,并从子模块引用该依赖项而无需指定版本或范围或其他任何内容。

Gradle 中有哪些替代方案?

【问题讨论】:

【参考方案1】:

您可以在父脚本中声明公共依赖项:

ext.libraries = [ // Groovy map literal
    spring_core: "org.springframework:spring-core:3.1",
    junit: "junit:junit:4.10"
]

然后,您可以从子脚本中使用依赖项声明,如下所示:

dependencies 
    compile libraries.spring_core
    testCompile libraries.junit

要与高级配置选项共享依赖声明,您可以使用DependencyHandler.create

libraries = [
    spring_core: dependencies.create("org.springframework:spring-core:3.1") 
        exclude module: "commons-logging"
        force = true
    
]

多个依赖可以同名共享:

libraries = [
    spring: [ // Groovy list literal
        "org.springframework:spring-core:3.1", 
        "org.springframework:spring-jdbc:3.1"
    ]
]

dependencies compile libraries.spring 将同时添加两个依赖项。

您不能以这种方式共享的一条信息是应将依赖项分配给什么配置(Maven 术语中的范围)。但是,根据我的经验,最好还是明确一点。

【讨论】:

谢谢,这解决了我的问题,但仍然有一个问题。在 Maven 中,我们可以将版本留空,如果这是一个库,这很方便,因为您可以在我们的应用程序中使用它并制作依赖管理来定义它应该采用什么版本的库。你会如何使用 Gradle 做同样的事情? 我不明白这个问题。请举个例子。 Peter,ctapobep 的意思是,在 maven 中,您可以在 dependencyManagement 部分的父(或聚合器)pom 中声明具有版本(和范围)的依赖关系。然后在“具体”的 pom 中,你不需要重新声明版本;只是工件和 groupId。基本上它告诉 maven “我需要 X:Y,但使用父配置的任何版本。” 为了避免这种重复,我倾向于创建一个单独的dependencies.gradle 脚​​本,在其中我将所有依赖项定义为属性,例如:ext.GROOVY = 'org.codehaus.groovy:groovy-all:2.1.6'。在根项目build.gradle 中,我包含allprojects  apply from: "$rootDir/dependencies.gradle" 。然后将所有依赖项定义在一个文件中,而不是分散在一个文件中,并且在依赖项配置中使用更多“易于阅读”的常量。 这正是我上面所做的。您无需申请allprojects,因为项目级别的额外属性对子项目可见。【参考方案2】:

从 Gradle 4.6 开始,文档中建议使用依赖约束作为实现此目的的方法。来自https://docs.gradle.org/current/userguide/declaring_dependencies.html#declaring_a_dependency_without_version:

对于大型项目,推荐的做法是声明不带版本的依赖项,并使用依赖项约束进行版本声明。好处是依赖约束允许你在一个地方管理所有依赖的版本,包括传递的。

在你的父 build.gradle 文件中:

allprojects 
  plugins.withType(JavaPlugin).whenPluginAdded 
    dependencies 
      constraints 
        implementation("com.google.guava:guava:27.0.1-jre")
      
    
  

使用检查 Java 插件 (...whenPluginAdded ) 包装依赖项块并不是绝对必要的,但它会处理将非 Java 项目添加到同一构建中。

然后在子 gradle 项目中,您可以简单地省略版本:

apply plugin: "java"

dependencies 
  implementation("com.google.guava:guava")

子构建仍然可以选择指定更高的版本。如果指定了较低版本,则会自动升级到约束中的版本。

【讨论】:

Gralde 4.6 中添加了依赖约束,因此这适用于 Gradle 4.6 或更高版本。 我认为 Gradle 规定在这种情况下使用 Java Platform Plugin。但是,Gradle 文档目前还不是很清楚。我想allprojects 的用法也很好。 我想在根项目中声明约束,但只在我的一个子项目中,我想加载所有定义了约束的依赖项。【参考方案3】:

这是一个迟到的回复,但您可能还想看看:http://plugins.gradle.org/plugin/io.spring.dependency-management 它提供了导入 maven 'bom' 的可能性,并重用 'bom' 中定义的定义。 当逐渐从 maven 迁移到 gradle 时,这当然是一个很好的帮助!现在很享受。

【讨论】:

当您想在多个(多)项目之间共享相同的依赖项时,它甚至是必不可少的。 虽然很方便,但这个插件可能会占用大量的性能。对于具有 200 多个依赖项的 30 个子项目,依赖项解析阶段最多需要 1 分钟。不过,对于小型项目,它就像一种魅力 它还覆盖了传递依赖版本,假设您在依赖管理中声明了 3.0.0 版本,但是对于其中一个子项目,您需要使用旧版本,例如 2.5.0,那么如果您有一个依赖于这个旧项目的项目,传递依赖将从 2.5.0 覆盖到依赖管理插件中声明的内容,因此在这种情况下 3.0.0 是一个非常奇怪的行为【参考方案4】:

io.spring.gradle:dependency-management-plugin 插件在新的 Gradle 3.x 系列中存在问题,但在 2.x 系列中稳定。参考错误报告Drop support for Gradle 3 #115

如果是 Spring (main promoter of BOM usage),您可能会以:

buildscript 
    repositories 
        mavenLocal()
        jcenter()
    
    dependencies 
        classpath 'io.spring.gradle:dependency-management-plugin:1.0.0.RELEASE'
    


repositories 
    mavenLocal()
    jcenter()


apply plugin: 'java'
apply plugin: 'io.spring.dependency-management'

dependencyManagement 
    imports 
        mavenBom 'io.spring.platform:platform-bom:Athens-SR3'
    


dependencies 
    compile 'org.springframework.boot:spring-boot-starter-web'

    testCompile 'org.springframework.boot:spring-boot-starter-test'

注意 io.spring.platform:platform-bomorg.springframework.boot:spring-boot-starter-parent 作为父级,因此它与 Spring Boot 兼容

您可以通过以下方式验证实际的依赖关系解析:

$ gradle dependencies
$ gradle dependencies --configuration compile
$ gradle dependencies -p $SUBPROJ

$ gradle buildEnvironment
$ gradle buildEnvironment -p $SUBPROJ

或有任务:

task showMeCache 
    configurations.compile.each  println it 

阅读Soring官方博文Better dependency management for Gradle,了解引入io.spring.gradle:dependency-management-plugin的原因。

【讨论】:

【参考方案5】:

我更喜欢在根项目中创建 common_dependencies.gradle 文件,其中包含内容

buildscript 
ext 
    commonDependencies = [
            redis      : 'redis.clients:jedis:3.6.3',
            lettuce    : 'io.lettuce:lettuce-core:6.1.4.RELEASE'
      ]
   

然后在根/子模块的 build.gradle

apply from: rootProject.file("common_dependencies.gradle")

dependencies 
    commonDependencies.values().forEach 
        implementation it
    

【讨论】:

【参考方案6】:

您可以使用以下代码集中依赖项:

gradle.properties

COMPILE_SDK_VERSION=26
BUILD_TOOLS_VERSION=26.0.1
TARGET_SDK_VERSION=26
MIN_SDK_VERSION=14

android_SUPPORT_VERSION=26.0.2

在每个模块中添加build.gradle

android 
    compileSdkVersion COMPILE_SDK_VERSION as int
    buildToolsVersion BUILD_TOOLS_VERSION as String

    defaultConfig 
        minSdkVersion MIN_SDK_VERSION as int
        targetSdkVersion TARGET_SDK_VERSION as int
        versionCode 1
        versionName "1.0"

    



dependencies 
 compile "com.android.support:appcompat-v7:$ANDROID_SUPPORT_VERSION"
 compile "com.android.support:support-v4:$ANDROID_SUPPORT_VERSION"
 compile "com.android.support:support-annotations:$ANDROID_SUPPORT_VERSION"
 compile "com.android.support:support-vector-drawable:$ANDROID_SUPPORT_VERSION"
 compile "com.android.support:design:$ANDROID_SUPPORT_VERSION"

【讨论】:

【参考方案7】:

这篇博文建议将依赖项和组作为配置进行管理: https://www.javacodegeeks.com/2016/05/manage-dependencies-gradle-multi-project-build.html

我自己没试过,但看起来很有趣。

根项目 build.gradle

subprojects 
  configurations 
    commonsIo
  

  dependencies 
    commonsIo 'commons-io:commons-io:2.5'
  

子项目build.gradle

configurations 
  compile.extendsFrom commonsIo

【讨论】:

【参考方案8】:

从 gradle 7.1.1 开始,您可以使用版本目录

https://docs.gradle.org/current/userguide/platforms.html

https://melix.github.io/blog/2021/03/version-catalogs.html

【讨论】:

【参考方案9】:

正如 datta 在 their answer 中所说,Gradle 现在有一个叫做版本目录的东西。 这是 Kotlin DSL (*.kts) 的示例。请注意,我使用的是 Gradle 7.4。

settings.gradle.kts中定义依赖关系:

// Configure dependencies aspects applied to all projects
dependencyResolutionManagement 
    // By default, repositories declared by a project will override the ones here.
    // You can change this behavior with the repositoriesMode property.
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)

    // Define repositories for all projects
    repositories 
        mavenCentral()
        maven("https://jitpack.io")
    

    versionCatalogs 
        create("libs") 
            // Versions are useful specially when you have libraries with the same
            // group and version which are updated together with the same version
            version("room", "2.4.1")
            //       │       │
            //       │       └───> The version notation
            //       └───> Your desired name (alias)
    
            library("material", "com.google.android.material:material:1.4.0")
            //       │           │
            //       │           └───> The dependency notation (coordinates)
            //       ├───> Your desired name (alias); only letters, digits and _ - .
            //       └───> Note that _ - . will all be normalized to .
    
            // You can configure the version as you would in regular build file
            // Note that the group and module are separate parameters
            library("junit5", "org.junit.jupiter", "junit-jupiter").version 
                prefer("5.8.0")
            
    
            // Using the same version for multiple dependencies
            library("room-ktx", "androidx.room", "room-ktx").versionRef("room")
            library("room-runtime", "androidx.room", "room-runtime").versionRef("room")
        
    

build.gradle.kts中的使用:

dependencies 
    implementation(libs.material)
    implementation(libs.room.ktx)
    implementation(libs.room.runtime)
    testImplementation(libs.junit5)

如您所见,您不仅可以声明依赖关系,还可以在此处声明存储库(而不是在***构建脚本中使用allprojects 块来定义所有子项目的存储库)。

有关上述解决方案的常规语法以及有关版本目录和集中存储库和依赖项配置的更多信息,请参阅Gradle official guides。

【讨论】:

【参考方案10】:

为了让您的 gradle 文件保持干净,我们可以将依赖项分组到一个数组中并在以后实现它们。

    在依赖块之外的build.gradle(应用级别)中添加类似这样的库版本

// 声明库的版本

final RetrofitVersion = '2.3.0'
final OkHttpVersion = '3.9.1'
    创建相关依赖的数组,方便以后查找。将其添加到依赖块之外的build.gradle(应用级别)

// 在库中使用版本并添加依赖和访问权限 名称(如改造(第一个))

final networkDependencies = [
        retrofit             : "com.squareup.retrofit2:retrofit:$RetrofitVersion",
        retrofitGsonConverter: "com.squareup.retrofit2:converter-gson:$RetrofitVersion",
        retrofitRxJavaAdapter: "com.squareup.retrofit2:adapter-rxjava2:$RetrofitVersion",
        okHttp3              : "com.squareup.okhttp3:okhttp:$OkHttpVersion",
        okHttp3Logging       : "com.squareup.okhttp3:logging-interceptor:$OkHttpVersion"
]
    依赖块中:

// 实现数组中的所有依赖

dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation networkDependencies.values()


所以最终代码将如下所示:

final RetrofitVersion = '2.3.0'
final OkHttpVersion = '3.9.1'

final networkDependencies = [
        retrofit             : "com.squareup.retrofit2:retrofit:$RetrofitVersion",
        retrofitGsonConverter: "com.squareup.retrofit2:converter-gson:$RetrofitVersion",
        retrofitRxJavaAdapter: "com.squareup.retrofit2:adapter-rxjava2:$RetrofitVersion",
        okHttp3              : "com.squareup.okhttp3:okhttp:$OkHttpVersion",
        okHttp3Logging       : "com.squareup.okhttp3:logging-interceptor:$OkHttpVersion"
]

dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation networkDependencies.values()

【讨论】:

如何通过这个包含注释处理器??就像龙目岛一样

以上是关于在 Gradle 中,如何在一个地方声明公共依赖项?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Gradle 版本目录知道是不是存在依赖项更新

Gradle:如何将带有子路径的 sourceControl 定义为依赖项?

Gradle 多项目在根项目中定义依赖项

用于依赖项的 Gradle 私有存储库

如何在 gradle 中重用 pom.xml 中定义的依赖项

Gradle:获取传递依赖项并导出到最小的运行时 fat jar