Gradle的惰性配置指推迟属性值计算和任务/插件配置至真正需要时才触发,通过Provider/Property替代直接赋值、使用plugins块代替apply、延迟依赖与路径解析等方式,显著缩短配置阶段耗时。

Gradle 的 lazy configuration(惰性配置)不是“等用到再写”,而是指**推迟属性值的计算和任务/插件的实际配置,直到真正需要时才触发**。它能显著缩短配置阶段耗时,尤其对大型多模块项目效果明显——因为配置阶段不再遍历所有 task、不提前解析未用到的属性,避免了大量无效计算。
为什么惰性配置能提速?
Gradle 构建分三阶段:初始化 → 配置 → 执行。配置阶段会执行所有 build.gradle 中的代码(比如 tasks.register、android {} 闭包、dependencies {}),哪怕某个 task 根本没被调用。传统写法中,直接赋值或调用方法(如 project.version = '1.0' 或 task.dependsOn 'otherTask')会立即求值;而惰性配置让这些操作延迟到执行阶段甚至更晚,减少配置期开销。
核心写法:用 Provider 和 Property 替代直接赋值
Gradle 提供了 Provider(只读延迟值)和 Property(可变延迟值)两类接口,它们支持链式转换、延迟绑定,且天然兼容增量构建和缓存:
-
不要这样写(立即求值):
version = project.property('VERSION_NAME').get()—— 一进配置阶段就去读系统属性,失败则报错,且无法延迟 -
应该这样写(惰性绑定):
version = providers.systemProperty('VERSION_NAME').forUseAtConfigurationTime().orElse('1.0')—— 只在真正需要 version 时才读取,且允许 fallback - 自定义 task 属性也应声明为
Property或RegularFileProperty,而非String或File - 依赖声明推荐用
implementation(project(":lib"))而非implementation project(':lib')—— 前者返回 Provider,后者立即解析项目路径
常见场景下的惰性改写示例
以下是一些高频但易踩坑的配置点,改用惰性方式后可规避不必要的计算:
-
动态版本号:用
providers.environmentVariable("CI_BUILD_NUMBER")替代System.getenv("CI_BUILD_NUMBER") -
文件路径拼接:用
layout.projectDirectory.dir("src/main/resources")替代file("src/main/resources") -
task 间依赖:用
dependsOn(tasks.named("prepareAssets"))替代dependsOn("prepareAssets")—— 后者会强制提前创建该 task -
Android 插件配置:在
android {}中,用namespace = providers.gradleProperty("ANDROID_NAMESPACE").getOrElse("com.example.app")替代硬编码或project.property()直接取值
配合 plugins {} 块使用效果更佳
Gradle 推荐用 plugins { id "com.android.application" version "8.7.0" } 代替 apply plugin: "com.android.application"。前者是预编译插件注册,支持按需加载、避免全局作用域污染;后者会在配置阶段立即加载插件并执行其全部逻辑,容易拖慢速度。两者本质区别在于:plugins 块本身是惰性的,只有当对应插件功能被首次引用时,才会触发实际配置。
不复杂但容易忽略,关键在于把“值”变成“获取值的动作”,让 Gradle 自己决定何时执行。











