推荐 9 个 Gradle 优秀实践,进阶必备!

2023年 10月 7日 18.7k 0

1.使用 Gradle 包装器

包装器是项目中包含的特殊脚本,用于下载正确的 Gradle 版本并执行构建。

使用包装器有 3 大优点:

  • 不需要在本地安装 Gradle 来进行构建
  • 可以始终使用项目支持的 Gradle 版本。
  • 更新Gradle版本很容易
  • 如果你的项目中当前没有包装器,在 Linux 中可以通过运行 ./gradlew 来添加,在Windows 中使用 gradlew.bat ,那么就不会出错。

    2.停止清理项目

    如果你每次构建时都执行清理,那么会造成极大的时间浪费,如下:

    ./gradlew clean build

    Gradle 有一个很的强功能,称为增量构建,意味着如果更改项目中的某些内容并运行构建,它只会根据该更改运行必要的任务。例如,如果只修改测试类,Gradle 不需要重新编译生产代码。增量构建意味着微小的更改构建速度会非常快,从而帮助开发人员完成更多工作。

    3.添加settings.gradle

    settings.gradle文件通常位于项目的根目录中,用于指定项目名称以及要添加到构建中的子项目。

    示例:

    rootProject.name = 'settings-example'
    
    include 'some-subproject'

    不过,settings.gradle是可选的。

    如果缺省该文件,Gradle 将会使用基于目录名称的项目名称,如果项目被克隆到不同名称的目录,则其项目名称将不正确。例如,这可能发生在 CI 服务器上。

    还有性能影响。如果省略settings.gradle,Gradle 会递归地在目录树中向上导航以查找此类文件。这可能会产生大量不必要的文件读取。

    4. 将任务移至buildSrc

    buildSrc目录位于项目的根目录中,可以包含 Groovy、Kotlin 或 Java 源代码。如果build.gradle中有一些任务代码,则可以转移到buildSrc,原因有 3 个:

    • 清理build.gradle,使其更容易理解
    • 将任务实现与声明分开
    • 对于多项目构建,任务可以在其他子项目中使用

    例如下面这个不太友好的 build.gradle 示例:

    abstract class RollercoasterTask extends DefaultTask {
        @Input
        abstract Property getFavouriteCoaster()
    
        RollercoasterTask() {
            favouriteCoaster.convention('Space mountain')
        }
    
        @TaskAction
        def tellMeMyFavourite() {
            println "Your favourite coaster is ${favouriteCoaster.get()}!"
        }
    }
    
    tasks.register('coaster', RollercoasterTask) {
        favouriteCoaster = 'Super-duper loopy coaster'
    }

    随着build.gradle 的增长,这种代码会让你头晕目眩。解决办法就是在与build.gradle相同的级别创建buildSrc目录,结构如下:

    ├── build.gradle
    ├── buildSrc
    │   └── src
    │       └── main
    │           └── groovy
    │               └── com
    │                   └── tomgregory
    │                       └── RollercoasterTask.groovy

    可以将类定义从build.gradle转移到RollercoasterTask.groovy中。只需包含相关的package和import 即可。如下:

    package com.tomgregory
    
    import org.gradle.api.DefaultTask
    import org.gradle.api.provider.Property
    import org.gradle.api.tasks.Input
    import org.gradle.api.tasks.TaskAction
    
    abstract class RollercoasterTask extends DefaultTask {
        @Input
        abstract Property getFavouriteCoaster()
    
        RollercoasterTask() {
            favouriteCoaster.convention('Space mountain')
        }
    
        @TaskAction
        def tellMeMyFavourite() {
            println "Your favourite coaster is ${favouriteCoaster.get()}!"
        }
    }

    在build.gradle中,可以用单个 import 语句替换类定义。

    import com.tomgregory.RollercoasterTask
    
    tasks.register('coaster', RollercoasterTask) {
        favouriteCoaster = 'Super-duper loopy coaster'
    }

    这样就清晰多了。

    5. 并行运行测试

    可以充分利用可用的 CPU 内核来并行运行测试,build.gradle 添加如下配置:

    test {
        maxParallelForks 3
    }

    完成此操作后,Gradle 将会并行执行测试。这里配置了3个执行器,可根据实际配置此参数。

    6. 项目进行版本化

    对 Gradle 项目进行版本控制可以让你更轻松地了解何时引入了更改。当其他人使用你的项目时,这一点尤其重要。

    例如,Gradle 本身使用相当标准的版本号系统,其中包括主版本、次版本和补丁版本。

    这样做的好处是 Gradle 用户,在升级 Gradle 时可以轻松了解更改的范围。当主要版本增加时,这表明可能会有重大更改,我们应该阅读发行说明。

    在 Gradle 中,设置版本号是在build.gradle中完成的,如下所示:

    version = '0.1.0'

    7. 将任务声明封装在插件中

    任务声明是创建某个任务类的实例时,通常配置一些任务属性。

    如下创建了一个名为copyQuote的 Copy 任务:

    project.tasks.register('copyQuote', Copy) {
        from 'quote.txt'
        into "$project.buildDir/quotes"
        filter(ReplaceTokens, tokens: [CHARACTER: 'Tweedledee'])
    }

    事实上,在build.gradle中声明此任务可能会导致几个问题:

    • 额外的代码使得从高层次理解build.gradle变得更加困难
    • 如果在不同的子项目中声明类似的任务,可能会出现重复

    解决方案是将逻辑移至插件中,如果只需要在自己的项目(而不是其他项目)中使用该插件,则可以在buildSrc目录中定义它。

    .
    ├── build.gradle
    ├── buildSrc
    │   └── src
    │       └── main
    │           ├── groovy
    │           │   └── com
    │           │       └── tomgregory
    │           │           ├── WonderlandPlugin.groovy

    将copyQuote任务移动到插件类中,代码如下:

    package com.tomgregory
    
    import org.apache.tools.ant.filters.ReplaceTokens
    import org.gradle.api.Plugin
    import org.gradle.api.Project
    import org.gradle.api.tasks.Copy
    
    class WonderlandPlugin implements Plugin {
        void apply(Project project) {
            def extension = project.extensions.create('wonderland', WonderlandPluginExtension)
    
            project.tasks.register('copyQuote', Copy) {
                from 'quote.txt'
                into "$project.buildDir/quotes"
                filter(ReplaceTokens, tokens: [CHARACTER: extension.characterName.get()])
            }
        }
    }

    现在build.gradle可以大大简化。

    plugins {
        id 'wonderland'
    }
    
    wonderland {
        characterName = 'Tweedledee'
    }

    8. 优化存储库

    在build.gradle中声明存储库告诉 Gradle 应该在哪里查找构建应用程序所需的依赖项。

    例如,在这里我们告诉 Gradle 查看我的自定义本地 Maven 存储库和 Maven Central。

    repositories {
        maven {
            name = 'tomRepo'
            url 'http://localhost:8081/repository/snapshots'
            allowInsecureProtocol true
            credentials(PasswordCredentials)
        }
        mavenCentral()
    }

    假设同一个项目需要这些依赖项来构建 Java 应用程序。

    dependencies {
        implementation group: 'com.tom', name: 'artifact-to-publish', version: '1.0-SNAPSHOT'
        implementation 'commons-lang:commons-lang:2.6'
        implementation 'com.google.guava:guava:30.1.1-jre'
        implementation 'org.mapstruct:mapstruct:1.4.2.Final'
        implementation 'org.hibernate:hibernate-validator:7.0.1.Final'
    }

    第一个依赖项来自本地 Maven 存储库,但其他依赖项可在 Maven Central 中找到。

    9. 切勿提交密码

    你是否曾经将密码提交到版本控制中然后遭受领导的鄙夷,或者被安全公司审查出安全问题。接下来我们将介绍如何避免。

    不过,这已经成为过去,因为 Gradle 提供了许多我们可以将凭证移出项目的方法。

    示例:

    repositories {
        maven {
            name = 'tomsRepo'
            url 'https://xxx.com/maven/demo/'
            credentials(PasswordCredentials)
        }
    }

    那么 Gradle 将自动查找属性Username和Password.

    你可以在命令行上传递这些参数或在~/.gradle/gradle.properties中设置,如下:

    // gradle.properties 中配置
    tomsRepoUsername=myusername
    tomsRepoPassword=mypassword

    另一种方法是直接访问 Gradle 属性:

    repositories {
        maven {
            url 'https://xxx.com/maven/demo/'
            credentials {
                username 'toms'
                password property('mypw')
            }
        }
    }

    在命令行或~/.gradle/gradle.properties中传递密码。

    命令行示例:

    ./gradlew build --refresh-dependencies -Pmypw=

    在~/.gradle/gradle.properties示例:

    mypw=mypassword

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论