Gradle 理解:configuration、dependency

47 篇文章 0 订阅
14 篇文章 1 订阅

一、什么是 dependency 的 configuration

不同的 configuration 用来引用不同领域(或不同用途)的 dependencies

如:implementation、api、testRuntime。

或者说 configuration 用来管理一批 dependencies。

二、configuration 的继承与复合

一个 configuration 可以继承另一个 configuration。子 configuration 会继承父 configuration 的所有 dependencies。

如 a 继承了 b(通过 extendsFrom 方法来继承):

configurations {
   a.extendsFrom b
}

在 java 插件中,compileClasspath 继承了 implementation,拥有了其声明的所有 dependencies。compileJava task 会用到 compileClasspath
在这里插入图片描述

三、可解析和可消费 configuration

configuration 可用于三个方面:

  • 单纯地声明 dependencies
  • 被消费者使用,将其管理的一组 dependencies 解析为文件
  • 被生产者使用,公开其管理的 artifacts 及其 dependencies 以供其他项目使用

一个可被解析的 configuration 的 canBeResolved 属性为 true。
一个可被消费的 configuration 的 canBeConsumed 属性为 true。

configurations {
	a {	canBeResloved = true }
	
	b { canBeConsumed = true }
}

一个可被解析 configuration 往往继承了一个或多个不可被解析 configuration。它们的关系类似于抽象类和子类:不可被解析 configuration 不能实例化,可解析 configuration 是它的子类,可实例化(将 dependencies 解析为文件)。

所以可被解析 configuration 用于管理 dependency,相应的,可被消费 configuration 用于管理 artifact。

canBeResolved、canBeConsumed 属性默认都为 true。
java 插件中,implementation 的 canBeResolved、canBeConsumed 属性都为 false。

四、自定义 configuration

4.1 现有 configuration 的继承

configurations {
	// 声明一个自定义 configuration
    gdConfiguration
    // 使 implementation 继承于它
    implementation.extendsFrom(gdConfiguration)
}

dependencies {
    // 使用自定义 configuration: gdConfiguration
    // mylib 中的类可以在 app 中正常访问
    gdConfiguration project(":mylib")
}

4.2 自定义 configuration 的解析

configurations {
   jasper
}

dependencies {
   jasper 'com.github.bumptech.glide:glide:4.9.0'
}

task preCompileJasper {
   doLast {
       // asPath 会触发 resolve
       println("configurations.jasper.asPath: ${configurations.jasper.asPath}")
   }
}

执行 preCompileJasper:

> Task :app:preCompileJasper
configurations.jasper.asPath: ~/.gradle/caches/modules-2/files-2.1/com.github.bumptech.glide/glide/4.9.0/c34f3a0b710a00c62a62683f5f756e6af34183a8/glide-4.9.0.aar:...

asPath 会下载引用的依赖(即 resolve),返回下载后的文件地址。
asPath 即 FileCollection 的 getAsPath() 方法。

如果设置 jasper 的 canBeResolved 属性为 false,执行 preCompileJasper 会失败:

> Task :app:preCompileJasper FAILED
* What went wrong:
Execution failed for task ':app:preCompileJasper'.
> Resolving configuration 'jasper' directly is not allowed

五、dependencies 的种类

5.1 module dependencies

module dependencies 是最常见的 dependencies,指向仓库中的某个 module。

dependencies {
    runtimeOnly group: 'org.springframework', name: 'spring-core', version: '2.5'
    runtimeOnly 'org.springframework:spring-core:2.5',
            'org.springframework:spring-aop:2.5'
    runtimeOnly(
        [group: 'org.springframework', name: 'spring-core', version: '2.5'],
        [group: 'org.springframework', name: 'spring-aop', version: '2.5']
    )
    runtimeOnly('org.hibernate:hibernate:3.0.5') {
        transitive = true
    }
    runtimeOnly group: 'org.hibernate', name: 'hibernate', version: '3.0.5', transitive: true
    runtimeOnly(group: 'org.hibernate', name: 'hibernate', version: '3.0.5') {
        transitive = true
    }
}

可以使用一个 String 或一个 Map 来声明 module dependencies,还可以加上一个配置闭包来补充配置。

map 的所有 key 见 dependencyHandler

5.2 文件 dependencies

可以直接将一个文件看作 dependency。

dependencies {
    antContrib files('ant/antcontrib.jar')
    externalLibs files('libs/commons-lang.jar', 'libs/log4j.jar')
    deploymentTools(fileTree('tools') { include '*.exe' })
    implementation fileTree(include: ['*.jar'], dir: 'libs')
}

这里注意,一种常见的 aar 的引入方式是:

implementation(name: 'library_1.2', ext: 'aar')

这其实不是一个文件 dependencies,而是一个 module dependency,需要将 aar 的目录设为 flatDir 仓库。

如果引用 jar 包时加上 aar,那其实也不用每个 aar 都单独声明:

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

当声明一个文件 dependency 时,可以通过 builtBy 来声明生产这个文件的 task:

configurations {
    myConfiguration
}

dependencies {
    myConfiguration files("$buildDir/classes") {
        builtBy 'myCompile'
    }
}

task myCompile() {
    doLast {
        println "myCompile exec"
    }
}

task list(dependsOn: configurations.myConfiguration) {
    doLast {
        // dependsOn 会触发 resolve
        // collect 也会触发 resolve
        println "classpath = ${configurations.myConfiguration.collect { File file -> file.name }}"
    }
}

这样,在 resolve 这个 configuration 时,它 builtBy 的 task 会先执行。

执行 list:

$ ./gradlew list
> Task :app:myCompile
myCompile exec

> Task :app:list
classpath = [classes]

如上,会先执行 myCompile,再执行 list。

5.3 Project dependencies

在 project 自己的 build.gradle 中声明:

dependencies {
   implementation project(':shared')
}

在其他 project 的 build.gradle 中声明:

project(":app") {
    dependencies {
        implementation project(':shared')
    }
}

一个 module dependencies 可以被该 module 的本地源码代替,即通过 project dependencies 代替 module dependencies,具体可查看 composite_builds

5.4 Gradle 特定 dependencies

Gradle 提供了几个特定的 dependencies。

dependencies {
   implementation gradleApi() // 声明一个当前 Gradle 版本 api 的依赖,用于开发自定义 Gradle task 或 plugin
   implementation localGroovy() // 声明一个当前 Gradle 版本使用的 Groovy 的依赖,用于开发自定义 Gradle task 或 plugin
   testImplementation gradleTestKit() // 声明一个当前 Gradle 版本使用的 TestKit 的依赖,用于测试 Gradle plugin 或 build script
}

六、文档化 dependencies

Gradle 4.6 及以后支持 because 关键字,用于说明使用某个 dependencies 的原因:

dependencies {
    implementation('org.ow2.asm:asm:7.1') {
        because 'we require a JDK 9 compatible bytecode generator'
    }
}

在使用 dependency insight 时,分析报告中会含有 because 的内容。

./gradlew :app:dependencyInsight --configuration debugCompileClasspath --dependency asm
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值