文章目录
一、什么是 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