Gradle面试题

Gradle面试题


序号内容链接地址
1Java面试题https://blog.csdn.net/golove666/article/details/137360180
2JVM面试题 https://blog.csdn.net/golove666/article/details/137245795
3Servlet面试题 https://blog.csdn.net/golove666/article/details/137395779
4Maven面试题 https://blog.csdn.net/golove666/article/details/137365977
5Git面试题https://blog.csdn.net/golove666/article/details/137368870
6Gradle面试题https://blog.csdn.net/golove666/article/details/137368172
7Jenkins 面试题 https://blog.csdn.net/golove666/article/details/137365214
8Tomcat面试题 https://blog.csdn.net/golove666/article/details/137364935
9Docker面试题 https://blog.csdn.net/golove666/article/details/137364760
10多线程面试题 https://blog.csdn.net/golove666/article/details/137357477
11Mybatis面试题 https://blog.csdn.net/golove666/article/details/137351745
12Nginx面试题 https://blog.csdn.net/golove666/article/details/137349465
13Spring面试题 https://blog.csdn.net/golove666/article/details/137334729
14Netty面试题https://blog.csdn.net/golove666/article/details/137263541
15SpringBoot面试题https://blog.csdn.net/golove666/article/details/137192312
16SpringBoot面试题1 https://blog.csdn.net/golove666/article/details/137383473
17Mysql面试题 https://blog.csdn.net/golove666/article/details/137261529
18Redis面试题 https://blog.csdn.net/golove666/article/details/137267922
19PostgreSQL面试题 https://blog.csdn.net/golove666/article/details/137385174
20Memcached面试题 https://blog.csdn.net/golove666/article/details/137384317
21Linux面试题https://blog.csdn.net/golove666/article/details/137384729
22HTML面试题 https://blog.csdn.net/golove666/article/details/137386352
23JavaScript面试题 https://blog.csdn.net/golove666/article/details/137385994
24Vue面试题https://blog.csdn.net/golove666/article/details/137341572
25Ajax面试题https://blog.csdn.net/golove666/article/details/137421929
26Python面试题 https://blog.csdn.net/golove666/article/details/137385635
27Spring Cloud Alibaba面试题 https://blog.csdn.net/golove666/article/details/137372112
28SpringCloud面试题 https://blog.csdn.net/golove666/article/details/137345465
29RabbitMQ面试题 https://blog.csdn.net/golove666/article/details/137344188
30Dubbo面试题 https://blog.csdn.net/golove666/article/details/137346834
31Elasticsearch面试题https://blog.csdn.net/golove666/article/details/137348184
32Oracle面试题https://blog.csdn.net/golove666/article/details/137350452
33Android面试题https://blog.csdn.net/golove666/article/details/137358253
34Kafka面试题 https://blog.csdn.net/golove666/article/details/137358607
35ZooKeeper面试题 https://blog.csdn.net/golove666/article/details/137359255
36Kubernetes面试题 https://blog.csdn.net/golove666/article/details/137365540
37Flink面试题 https://blog.csdn.net/golove666/article/details/137369555
38Hadoop面试题https://blog.csdn.net/golove666/article/details/137370194
39Hive面试题https://blog.csdn.net/golove666/article/details/137371835
40Hbase面试题 https://blog.csdn.net/golove666/article/details/137381853
41Spark面试题https://blog.csdn.net/golove666/article/details/137382815
42Golang面试题 https://blog.csdn.net/golove666/article/details/137395486
43Solr面试题 https://blog.csdn.net/golove666/article/details/137420799

1 Gradle 基础知识

1.1 解释 Gradle 是什么及其与 Maven 的比较

什么是 Gradle?

Gradle 是一种先进的通用构建工具,它组合了 Ant 的灵活性以及 Maven 的约定优于配置的原则。Gradle 使用基于 Groovy 或 Kotlin 的 DSL(领域特定语言)来描述和操作构建逻辑,而不是像 Maven 那样依赖 XML。它被设计用来构建任何类型的软件,尤其是在 Android 应用开发中被广泛应用,成为官方的构建系统。

Gradle 的主要特点:

  1. 灵活性:Gradle 提供了高度的可定制性,使其适用于几乎所有类型的项目。

  2. 性能:通过使用构建缓存和增量构建技术,Gradle 旨在优化构建速度。

  3. 生态系统:拥有丰富的插件生态系统,以支持从简单项目到大型企业级应用的构建。

  4. 多语言支持:除了 Java,还能构建 Groovy、Kotlin、Scala 甚至非 JVM 语言的项目。

  5. 多项目构建:对于依赖于多个项目或模块的复杂结构,Gradle 能够轻松管理和构建这些依赖关系。

  6. 混合构建:能同时处理 Java 和原生代码的项目。

Gradle 与 Maven 的比较:

  1. 灵活性

    • Gradle:通过 Groovy 或 Kotlin 的 DSL 提供更高的灵活性和可扩展性。
    • Maven:遵循更严格的约定优于配置的方式,通过 XML 文件来管理构建过程,对于某些自定义过程可能会变得繁琐。
  2. 性能

    • Gradle:增量构建和构建缓存机制提高了性能,使得重新构建更快。
    • Maven:构建时间通常比 Gradle 更长,因为它缺少类似的构建缓存机制。
  3. 构建描述

    • Gradle:使用 DSL,构建脚本通常更易阅读和编写。
    • Maven:使用 XML,项目结构和依赖更加声明性,但对于复杂的构建脚本可能显得冗长。
  4. 项目结构

    • Gradle 和 Maven 都支持基于模块的项目,但 Gradle 在处理多项目构建时更为灵活。
  5. 依赖管理

    • Gradle 和 Maven 都提供强大的依赖管理工具,但 Gradle 提供更细粒度的控制功能。
  6. 易用性

    • Gradle 更加新颖,学习曲线可能稍微陡峭一点。
    • Maven 被广泛使用,有大量文档和社区支持,所以对很多人来说可能更容易上手。

虽然 Maven 在很多企业中有着坚实的用户基础,Gradle 由于其灵活性、性能和用户友好的特性,正在逐渐成为开发者的首选。特别是对于 Android 或使用 Kotlin 开发的项目,Gradle 提供了额外的集成和优势。在选择构建工具时,应考虑项目的需求、团队的经验以及工具的社区支持。

1.2 描述 Gradle 构建生命周期

Gradle 是一个灵活的构建自动化系统,它使用基于 Groovy 或 Kotlin DSL 的脚本来配置和执行构建任务。与 Maven 不同,Gradle 没有严格的生命周期模型,而是采取基于任务的方法来组织和运行构建逻辑。尽管如此,Gradle 的构建过程可以被概念性地划分为三个阶段:

初始化阶段(Initialization Phase)

在这个阶段,Gradle 确定哪些项目(Project)将被构建以及它们之间的关系。对于多项目构建来说,Gradle 会创建一个 settings.gradle 文件列出所有涉及的项目。该阶段主要是关于项目结构的设置。

配置阶段(Configuration Phase)

在配置阶段,Gradle 加载项目的 build.gradle 脚本,并构建一个任务图(Task Graph),这个任务图中包含了所有将要执行的任务及其依赖关系。每个任务都会在这个阶段进行配置,此时所有的任务都被加载和配置好了,但还没有执行。这个阶段是构建过程中最灵活的部分,可以根据需要配置插件、依赖和任务。

执行阶段(Execution Phase)

在执行阶段,基于任务图,Gradle 会执行所需的任务。此时 Gradle 会根据任务依赖关系和输入条件来确定哪些任务需要运行,然后按照顺序执行它们。构建脚本中定义的实际编译、测试、打包等操作会在这个阶段进行。

生命周期相关的任务和概念

  • Tasks: 在 Gradle 中,所有的构建步骤都是通过任务来表示的。你可以创建自定义任务或使用 Gradle 提供的内置任务。
  • Up-to-date Checks: Gradle 具有智能的增量构建机制,它检查任务的输入和输出来决定是否需要执行任务,从而提高构建效率。
  • Build Script: build.gradle 文件即是 Gradle 构建脚本,它在配置阶段加载与解析。
  • Settings Script: settings.gradle 文件用于配置 Gradle 的多项目构建,它在初始化阶段加载与解析。

优化 Gradle 构建性能

  • 并行执行: Gradle 可以并行运行多个项目的构建任务,以及跨项目的依赖关系解析。
  • 配置缓存: Gradle 2.0 及其以后的版本引入了配置缓存,在多次构建中复用已经完成的配置结果。
  • 构建扫描: 你可以使用 Gradle Enterprise 来分析和优化构建过程。

理解 Gradle 的构建过程和相应阶段对于编写高效的构建脚本非常重要,有助于合理安排任务顺序和逻辑,避免不必要的重构建,从而加快构建速度,改善开发体验。

1.3 讲述 Groovy 基础及其在 Gradle 中的应用

Groovy 是一种基于 JVM(Java 虚拟机)的敏捷开发语言,它融合了多种编程范式,包括面向对象、函数式和动态语言特性。Groovy 很大程度上与 Java 兼容,支持很多 Java 的特性,同时提供额外的便利性和简洁性。Groovy 在 Gradle 构建工具中被广泛应用。

Groovy 基础

以下是一些 Groovy 的基本特性:

1. 动态类型语言

Groovy 是一种动态类型语言,你可以选择不显示声明变量的类型。Groovy 编译器会在编译时自动推断变量的数据类型。

def greeting = 'Hello, World!' // 使用 def 关键字定义一个动态类型变量
println(greeting)
2. 脚本能力

Groovy 可以作为一门脚本语言立即执行,不需要定义类和方法。

3. 闭包(Closures)

闭包类似于 Java 8 的 Lambda 表达式,但提供了更多的灵活性和控制。

def list = [1, 2, 3, 4]
list.each { number ->
    println("Number is $number")
}
4. 集合 API

Groovy 对集合提供了丰富的 API,能够通过简洁的语法进行操作。

5. 操作符重载

Groovy 支持操作符重载,使得你可以定义如何用标准操作符(如 +-* 等)来处理自定义对象。

6. 条件和循环简化

Groovy 提供简化的语法来进行条件判断和循环控制。

7. 安全导航操作符

Groovy 引入了安全导航操作符 ?. 来访问可能为 null 的对象属性,避免 NullPointerException

8. GPath

在处理 XML 和 HTML 等方面,Groovy 的 GPath 表达式非常强大且易于使用。

Groovy 在 Gradle 中的应用

Gradle 是一个基于 Groovy DSL(域特定语言)的自动化构建工具,它使用 Groovy 去编写构建脚本。

1. 构建脚本

在 Gradle 中,构建逻辑是使用 Groovy 编写的 build.gradle 脚本来定义的。

2. DSL

Groovy 的动态特性使得 Gradle 能够为项目构建和依赖管理提供直观且易于阅读的 DSL。

apply plugin: 'java'

dependencies {
    compile 'org.springframework:spring-core:5.3.5'
}
3. 任务自定义

Groovy 闭包和动态特性使得在 Gradle 中定义和配置任务变得简单。

task myTask {
    doLast {
        println 'This is my custom task.'
    }
}
4. 配置和依赖管理

Gradle 利用 Groovy 的集合处理能力,使得配置项目依赖和插件管理变得非常灵活。

总结
Groovy 为创建动态和易于维护的应用程序提供了丰富的特性集。Gradle 则使用了 Groovy 的这些特性来提供一个强大的构建系统。通过 Groovy,Gradle 构建脚本更加易于编写和理解,特别适合于复杂和大型的项目构建。

2 Gradle 构建脚本

2.1 解释 Gradle Build Script 的组成

Gradle 是一个灵活的构建自动化工具,它在 Java、Groovy和Kotlin等多个编程语言中广泛使用。Gradle 构建脚本定义了项目构建过程中的任务、依赖和插件等。以下是 Gradle 构建脚本的主要组成部分:

项目声明

每个 Gradle 构建脚本都是从描述项目本身开始的,通常由一个 Project 实例代表。项目里定义了一系列的属性和方法,比如项目名称、版本以及要应用的插件。

插件应用

插件扩展了 Gradle 的核心功能,添加了新的任务类型和配置选项。以下是应用插件的示例:

plugins {
    // 应用 Java 插件
    id 'java'
    // 应用其他插件,附带版本信息
    id 'org.springframework.boot' version '2.3.1.RELEASE'
}

依赖配置

依赖声明了项目所依赖的外部库。有几种依赖配置,如 implementationtestImplementationapi 等,用来区分主代码和测试代码的依赖关系:

dependencies {
    // 添加主代码依赖
    implementation 'org.springframework.boot:spring-boot-starter-web'
    // 添加测试依赖
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

任务定义

任务是 Gradle 执行的基本工作单元。Gradle 提供了许多内建任务,用户也可以定义自定义任务:

task hello {
    doLast {
        println 'Hello, Gradle!'
    }
}

仓库设置

你需要指定至少一个仓库使 Gradle 能够找到依赖的二进制文件。常用的仓库包括 JCenter、Maven Central 等:

repositories {
    mavenCentral()
    jcenter()
    google()
}

多项目构建配置

在多项目构建中,Gradle 允许你配置每一个子项目或整个项目范围内的共享配置:

subprojects {
    // 子项目共享配置
}

配置阶段

Gradle 构建生命周期包括初始化阶段、配置阶段和执行阶段。在配置阶段,每个项目和任务都会被配置,任务依赖会被确定。

执行阶段

在执行阶段,Gradle 根据依赖图执行任务。打印出的构建报告和日志将提供任务执行的结果和相关信息。

额外配置

构建脚本还包括了对于构建环境和过程的其他配置,比如编译选项、打包配置等。

Gradle 构建脚本通常使用 DSL(领域特定语言)来描述构建逻辑。它具有非常强的表现力并且高度可配置,可以满足大部分构建自动化的需求。由于 Gradle 基于 Groovy 或 Kotlin 脚本编写,这为开发者提供了相对较高的灵活性。因此,对于复杂的构建需求,Gradle 构建脚本可以通过编程方式执行更为复杂的任务。

2.2 讨论 Gradle 中的任务(Tasks)和它们的配置

Gradle 是一个基于 Groovy 的构建自动化工具,它允许你定义一系列的任务(Tasks),以执行构建、测试和部署等操作。在 Gradle 中,一个 Task 代表了构建过程的一个原子步骤,如编译类、创建 JAR 文件或生成文档。

Gradle Task 基础

任务在 Gradle 构建脚本中被定义为以下形式:

task taskName {
    // 任务配置
}

你可以指定一个任务的行为、定义其依赖关系以及它所依赖的其他任务完成后才能执行的行为。

定义一个简单的 Task

下面是一个简单的任务示例,它在执行时会在控制台打印消息:

task hello {
    doLast {
        println 'Hello, Gradle!'
    }
}

doLast 方法(也可以用 << 运算符)定义了任务的行为,它会在任务执行时被调用。你也可以通过 doFirst 方法来定义在任务行为之前执行的动作。

添加 Task 依赖和顺序

任务可以相互依赖;一个任务的执行可以依赖于另一个任务的完成。使用 dependsOn 来声明依赖关系:

task compile {
    dependsOn clean
    doLast {
        // 编译源代码的逻辑
    }
}

task clean(type: Delete) {
    delete 'build'
}

在此示例中,compile 任务依赖于 clean 任务,clean 任务会删除构建目录。

Task 的输入和输出

可以为任务设置输入和输出,Gradle 通过这些设置来确定任务是否需要执行(增量构建)。

task processFiles {
    inputs.files file('src')
    outputs.dir file('dest')

    doLast {
        // 文件处理逻辑
    }
}

当输入或输出没有发生变化时,Gradle 可以决定跳过任务执行以提高构建速度。

配置 Task 属性

Gradle 允许你设置及获取 Task 属性,例如任务组和任务描述:

task deploy {
    group 'Deployment'
    description 'Deploys the application to the server'
    doLast {
        // 部署应用的逻辑
    }
}

这有助于任务的组织和在 Gradle 任务列表中的显示。

使用 Task 类型

Gradle 预定义了许多任务类型,用于常见的构建操作。你可以使用这些类型来定义具体的行为:

task createJar(type: Jar) {
    archiveBaseName = 'mylibrary'
    from sourceSets.main.output
}

在这个示例中,我们定义了一个类型为 Jar 的任务来创建 JAR 文件。

使用闭包配置 Task

Gradle 中的 Task 可以使用闭包来实现更复杂的配置逻辑。闭包可以访问和修改 Task 的属性:

tasks.named('build') {
    doLast {
        println 'Building project...'
    }
}

named 方法允许你配置一个已经存在的 Task。

创建任务依赖图

使用 Task 之间的依赖关系,Gradle 可以执行依赖计算并创建一个任务执行的图。执行 gradle tasks --all 可以列出所有任务及其依赖关系。

任务(Tasks)是 Gradle 构建的基础,它们使得构建过程可配置、可扩展并且模块化。了解如何定义和配置任务是使用 Gradle 进行高效构建的关键。通过组合多个任务,你可以创建一个强大的构建流程来满足你的自动化需求。

2.3 描述 Gradle 插件系统及其使用

Gradle 提供了一个强大的插件系统,它使得构建工具的核心功能可以通过插件进行扩展。Gradle 插件本质上是一组封装好的脚本,用以添加和配置任务、依赖管理、运行时属性和其他构建逻辑。

插件类型

Gradle 中有两种主要类型的插件:

  1. 脚本插件:简单的脚本文件,可以直接包含在构建脚本或者作为一个独立的文件。它们适用于简单的任务或在多个项目中共享常见的构建逻辑。
  2. 二进制插件:使用 Java 或 Kotlin 编写的更高级插件,它们通常通过 Gradle 插件门户(Plugin Portal)或者其他 Maven/Ivy 软件库进行分发。

使用插件

使用 Gradle 插件通常包括以下几个步骤:

应用脚本插件

build.gradle 文件中,您可以直接应用脚本插件:

// 应用位于 buildSrc 目录或外部文件的脚本插件
apply from: 'path/to/your/script.gradle'

或者行内定义插件逻辑:

// 应用位于 build.gradle 文件内的插件代码
apply plugin: 'java'
应用二进制插件

build.gradle 中使用 plugins DSL 应用二进制插件:

plugins {
    id 'com.android.application' version '4.0.0'
    id 'org.jetbrains.kotlin.android' version '1.4.0'
}

创建自定义二进制插件

要创建自定义的二进制插件,需创建一个实现 Plugin 接口的类:

public class GreetingPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        project.task('greet').doLast {
            println 'Hello from the GreetingPlugin!'
        }
    }
}

然后在构建脚本中应用这个自定义插件:

apply plugin: GreetingPlugin

发现和使用社区插件

Gradle 插件门户是发现和使用社区插件的官方网站。它提供了一个广泛的插件库,您可以在自己的项目中应用这些插件。

插件配置

插件可以提供配置选项,让您定制其行为。这通常通过 DSL 或在插件任务上的 configure 方法来实现:

greet {
    // 配置插件提供的自定义扩展或任务
    message = 'Hi from Gradle!'
}

插件依赖

如果您的插件依赖于其他插件,可以在插件的 apply 方法中声明其他插件:

public void apply(Project project) {
    project.apply plugin: 'java' // 依赖于 Java 插件
    // ...)
}

最佳实践

  • 保持插件的原子性:每个插件应该只关注一件事并做好它。
  • 避免插件间的隐式依赖:明确插件的依赖并在文档中指出。
  • 维护和版本控制:为自定义插件编写测试,并在版本发布时遵循语义化版本控制。
  • 文档化:提供清晰的文档说明插件的用途和配置方式。

通过使用 Gradle 的插件系统,可以将复杂的构建逻辑模块化和复用,同时提升构建的灵活性和可维护性。对于更高级的插件开发,Gradle 提供了完整的 API 和丰富的文档来支持您打造更为复杂和功能性的插件。

3 Gradle 依赖管理

3.1 描述 Gradle 的依赖管理机制

Gradle 的依赖管理机制是其构建系统的核心特性之一。它允许自动处理外部模块依赖(如 JAR 文件、库、项目),以及管理这些依赖的生命周期。Gradle 依赖管理主要包括以下方面:

声明依赖

在 Gradle 构建脚本中(通常是 build.gradle 文件),需要明确声明项目所需的依赖。通常,这些声明包括库的组名、名称和版本号。例如:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:2.3.1.RELEASE'
    testImplementation 'junit:junit:4.12'
}

在这个例子中,implementationtestImplementation 表示了不同的依赖配置,它们的作用范围不同。

依赖类型

Gradle 支持多种类型的依赖配置,包括但不限于 implementation(或 compile)、testImplementationruntimeOnly 等。每种配置都有其特定的用途,例如,implementation 用于编译和运行时代码,testImplementation 仅用于测试。

仓库配置

Gradle 需要知道在何处寻找声明的依赖,这通常通过配置仓库的方式实现。Gradle 可以从本地、远程以及 Maven 和 Ivy 仓库解析依赖。例如,配置 Maven 中央仓库:

repositories {
    mavenCentral()
    jcenter()
}

依赖解析

当运行构建时,Gradle 将按照构建脚本中的声明,在配置的仓库中解析依赖。如果依赖在本地缓存中不存在,Gradle 会下载它们并保存在本地缓存中,以便未来构建时重用,从而加速构建过程。

传递性依赖

Gradle 自动处理传递性依赖,即当你添加一个依赖时,该依赖所依赖的项目(依赖的依赖)也将被解析和下载。

冲突解决

当不同的依赖项要求同一个库的不同版本时,Gradle 需要决定使用哪个版本。默认情况下,Gradle 会使用“新版本优先”策略来解决依赖冲突。

后续操作

下载的依赖项被添加到构建路径(classpath),用于编译项目,在运行测试时,Gradle 也将包含相应的测试依赖。

通过上述机制,Gradle 提供了一种强大而灵活的依赖管理方式,可以适应从简单到非常复杂的项目需要。Gradle 的依赖管理不仅提高了开发效率,还简化了构建和发布过程。

3.2 讲述 Gradle Repository 配置

Gradle 使用仓库(repositories)来解析项目的依赖。你可以配置 Gradle 从不同类型的仓库中拉取依赖项,包含远程仓库和本地仓库。以下是一些常见类型的仓库配置方法:

远程仓库

  1. Maven Central:

    repositories {
        mavenCentral()
    }
    
  2. JCenter:

    repositories {
        jcenter()
    }
    
  3. 自定义 Maven 仓库:

    repositories {
        maven {
            url "http://mycompany.com/maven-repo"
        }
    }
    
  4. Google:

    repositories {
        google()
    }
    

本地仓库

  1. 本地 Maven 仓库:

    repositories {
        mavenLocal()
    }
    
  2. 本地文件系统中的仓库:

    repositories {
        flatDir {
            dirs 'libs', '~/my-libs'
        }
    }
    

    这样可以让 Gradle 从项目根目录下的 libs 文件夹以及用户目录下的 my-libs 文件夹查找依赖。

使用 Credentials 的仓库

如果连接到的 Maven 仓库需要认证,可以配置用户名和密码:

repositories {
    maven {
        url "http://mysecurecompany.com/maven-repo"
        credentials {
            username 'user'
            password 'password'
        }
    }
}

配置多个仓库

可以同时配置多个仓库,Gradle 会按照仓库声明的顺序解析依赖:

repositories {
    mavenLocal()
    jcenter()
    mavenCentral()
    google()
    maven {
        url "http://otherserver.com/maven-repo"
    }
}

在上述配置中,Gradle 首先在本地 Maven 缓存查找,然后依次访问 JCenter、Maven Central、Google Maven 等仓库。

Ivy 仓库

Gradle 也支持从 Ivy 类型的仓库解析依赖:

repositories {
    ivy {
        url "http://mycompany.com/ivy-repo"
    }
}

Gradle Wrapper 配置

gradle-wrapper.properties 文件通常会有一个 distributionUrl 属性来指定 Gradle 发行版的下载地址。可以配置为代理地址或公司内部发行的 Gradle 包。

支持的协议

  • Gradle 支持通过 HTTP 和 HTTPS 协议访问远程仓库。
  • 适当配置后,也支持其他协议如 file:// 用于本地仓库。

通过配置项目的 build.gradle(对于 Groovy 语法)或 build.gradle.kts(对于 Kotlin 语法)文件,你可以灵活地设置项目的依赖解析策略。正确配置仓库是确保 Gradle 高效运行的一项重要工作,选择适当的仓库可以提高依赖下载速度并确保构建的稳定性。

3.3 解释 Gradle 缓存机制和依赖解析策略

Gradle 是一个现代的构建工具,它大量地使用了缓存机制来优化构建的速度,减少不必要的操作。它的缓存机制包括本地构建缓存和远程构建缓存。

Gradle 缓存机制

1. 本地构建缓存

Gradle 的本地构建缓存能够在多次构建间缓存任务输出。当输入参数和任务的执行动作没有发生变化时,Gradle 会复用上一次构建中的输出。这可以节省时间,因为它避免了重复的构建执行。

2. 远程构建缓存

在多人开发或持续集成环境中,远程构建缓存特别有用。它们允许开发者和 CI 服务器共享可重复使用的构建结果,这样整个团队可以受益于缓存,从而改善构建性能。

3. 依赖缓存

Gradle 还缓存下载的依赖项(包括第三方库和插件)。默认情况下,这些依赖项存储在 ~/.gradle/caches 目录中。一旦下载,不会再次从远程仓库获取,除非要求的版本发生了变化。

Gradle 依赖解析策略

1. 灵活的依赖版本

Gradle 允许使用动态版本号的依赖解析,例如 'com.corp:library:1.+'。这种声明将会拿到 1.x 的最新版本。But, it is not recommended for reproducibility.

2. 依赖处理规则

Gradle 提供一系列的策略来处理项目依赖的冲突,比如通过 force 关键字强制使用特定版本的依赖。

3. 分辨(Resolution)策略

可以配置 Gradle 的分辨策略来处理库版本冲突。例如,你可以告诉 Gradle 总是选择最新的版本,或者你可以自定义一个规则,选择特定条件下的版本。

4. 短暂依赖(Transitive Dependencies)

Gradle 默认会解析传递性依赖,但可以配置为忽略它们,或通过 exclude 规则精简传递性依赖树。

5. 组件元数据规则

Gradle 允许自定义组件元数据规则,这可以更改 Gradle 对下载的模块元数据的解析方式。

最佳实践

  1. 构建环境隔离
    为确保一致性,建议为不同的项目配置独特的 Gradle 属性文件(gradle.properties)。

  2. 持续集成中的缓存配置
    当配置 CI 环境时,避免多个构建作业相互干扰,最好独立配置构建缓存。

  3. 避免动态版本
    为了稳定性和重现性,尽量避免在生产构建中使用动态版本声明。

  4. 定期清理缓存
    定期清理本地缓存可以避免磁盘空间被过时的构建存储占满。

  5. 使用组件元数据规则合理
    只在必要时使用组件元数据规则,避免过多定制带来的复杂性。

Gradle 通过这些缓存和解析策略显著提高了构建性能,为软件开发提供了快速和灵活的构建解决方案。正确配置和使用这些机制对于保持构建过程的效率至关重要。

4 Gradle 高级功能

4.1 分析 Gradle 多项目构建(Multi-Project Builds)

Gradle 多项目构建是用于同时管理和构建由多个相关子项目组成的大型项目。在多项目构建中,每个子项目可以有它自己的构建脚本,同时还可以从根项目继承配置或依赖信息,这样可以让整个项目更有序和易于管理。

以下是 Gradle 多项目构建的一些关键点和步骤:

设置根项目

根项目通常包含一个 settings.gradle(在 Gradle 7.0 以后建议命名为 settings.gradle.kts) 文件和一个 build.gradle(或 build.gradle.kts) 文件。

  • settings.gradle 文件定义了哪些子项目参与构建,并可以设置项目之间的关系:
rootProject.name = 'root-project'
include 'app', 'library'

在上述例子中,applibrary 是根项目下的两个子项目。

  • 根项目的 build.gradle 文件通常包含为多个子项目共享的通用构建逻辑。

子项目结构

每个子项目都有自己的目录,并且通常包含一个 build.gradle 文件来定义特有的构建脚本。目录结构示例:

root-project/          // 根项目
├── settings.gradle    // 定义了多项目构建设置
├── build.gradle       // 根项目的构建脚本
├── app/               // 子项目1: app
│   └── build.gradle   // app 的构建脚本
└── library/           // 子项目2: library
    └── build.gradle   // library 的构建脚本

子项目配置

  • 子项目可以通过 project 方法引用其他子项目,创建项目间的依赖关系。
dependencies {
    implementation project(':library')
}
  • 子项目的 build.gradle 文件还可以覆盖或扩展父项目 build.gradle 中定义的配置。

任务委派

  • 根项目可以定义任务,在多个子项目中执行。
task cleanAll { }
cleanAll.dependsOn subprojects*.clean

在上述示例中,cleanAll 任务会调用所有子项目中的 clean 任务。

子项目的共享配置

  • 子项目通常需要共享某些配置,如依赖版本、插件等。可以在根项目中使用 allprojectssubprojects 块来配置。
subprojects {
    apply plugin: 'java'

    repositories {
        mavenCentral()
    }

    version = '1.0'
}

上述配置会应用到所有子项目中。

继承与覆盖

  • 子项目可以继承父项目中的配置,也可以根据需要覆盖和添加特定配置。覆盖配置时要谨慎,避免破坏共享配置和继承关系。

运行多项目构建

  • 可以指定项目路径来仅构建特定的子项目。
gradle :app:build

上述命令仅会构建 app 子项目。

Gradle 的多项目构建系统非常灵活,能够处理复杂的项目结构,同时保持了构建逻辑的干净和易于维护。正确配置多项目构建,可以显著地提高构建过程的效率和一致性。

4.2 描述 Gradle 的自定义插件开发

在 Gradle 中,插件是一组封装了额外构建逻辑的可重用代码块。自定义插件开发可以用来封装构建逻辑,以便在多个项目中共享和重用。创建自定义 Gradle 插件的基本步骤如下:

1. 创建插件项目

创建一个新的 Gradle 项目或在现有项目中添加一个模块来开发你的插件。将这个项目或模块配置为生成一个 JAR 文件。

2. 定义插件类

插件可以通过实现 Plugin 接口来定义。创建一个 Java 或 Groovy 类实现 Plugin<Project> 接口。

public class GreetingPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        // 插件逻辑
    }
}

apply 方法里,你可以编写你的插件的逻辑,如添加任务、配置扩展属性或依赖管理。

3. 添加插件逻辑

在插件类中,你可以定义任务、扩展和依赖。比如创建一个名为 greet 的自定义任务:

project.getTasks().create("greet", Task.class, (task) -> {
    task.doLast(new Action<Task>() {
        @Override
        public void execute(Task task) {
            System.out.println("Hello from Greeting Plugin");
        }
    });
});

4. 声明插件标识符

resources/META-INF/gradle-plugins 目录下创建一个属性文件,其文件名是你希望给插件使用的 ID,文件内容指定了实现 Plugin 接口的类的全限定名。

假设你的插件 ID 为 com.example.greeting,则在 src/main/resources/META-INF/gradle-plugins/com.example.greeting.properties 文件内添加如下内容:

implementation-class=com.example.GreetingPlugin

5. 测试插件

在插件项目中创建一个测试用的 Gradle 构建脚本(或在一些集成测试中),然后引用并应用你的插件以确保它按预期工作。

apply plugin: 'com.example.greeting'

// 其他配置和任务

6. 构建并发布插件

一旦你的插件准备好了,你可以构建它并发布到本地仓库或 Maven Central、JCenter 或 Gradle Plugin Portal 等远程存储库。发布插件可能需要额外的配置,如版本控制和仓库认证信息。

7. 使用插件

发布后,你的插件可以在其他项目中通过插件标识符引用和使用。

plugins {
    id 'com.example.greeting' version '1.0.0'
}

自定义插件开发使你能够封装构建逻辑,简化和标准化项目的构建过程。同时,插件的开发提供了高度的灵活性和可扩展性,满足构建过程中的特定需求。通过在 Gradle Plugin Portal 上发布,你的插件甚至可以被广泛社区所使用。

4.3 讨论 Gradle 中的性能优化技术

Gradle 是一款功能丰富的构建工具,它提供了多种方式帮助你优化构建过程的性能。以下是 Gradle 中一些提高性能的技术和实践:

使用最新版本的 Gradle

Gradle 持续在新版本中进行性能优化。使用最新稳定版本的 Gradle 可以确保你享受到这些改进。

配置守护进程(Gradle Daemon)

Gradle 守护进程是一个长期运行的背景进程,它使得构建能够更快开始并减少了构建执行的时间。确保守护进程是启用的(默认情况下该设置是开启的)。

使用构建缓存

Gradle 构建缓存可以重用之前构建的输出,对于多项目构建和持续集成环境是非常有效的。

  • gradle.properties 中启用构建缓存:

    org.gradle.caching=true
    

配置编译和测试缓存

  • 配置 test 任务使用缓存:

    tasks.withType(Test) {
        useJUnitPlatform()
        cacheIf { true } // 根据需求可以有条件地设置缓存
    }
    
  • 对于 Java/Kotlin 编译任务,可以通过配置使其适用缓存。

优化依赖配置

  • 修剪和优化项目的依赖。移除不必要的依赖项可以减少 Gradle 解析和下载的时间。
  • 使用正确的依赖配置,比如 implementation 而非 compile,因为 compile 会被弃用并有更多的冗余构建效果。

并行执行

Gradle 提供了并行运行多个任务的能力,这样可以充分利用多核心处理器。

  • gradle.properties 中开启并行:

    org.gradle.parallel=true
    

禁用不必要的任务

如果项目中有一些不经常需要的任务,可以配置这些任务在需要的时候才运行。

使用 --configure-on-demand 标志

如果你有一个大型的多项目构建,--configure-on-demand 选项可以只为所需的项目进行配置。

避免使用动态依赖版本

指定清晰的依赖版本可以减少 Gradle 需要做的解析工作,同时提高构建的确定性。

减少 Gradle 日志输出

过多的日志会增加 I/O 负担,同时可能影响构建性能。只记录关键信息。

  • gradle.properties 中设置合适的日志级别:

    org.gradle.logging.level=warn
    

使用 snapshot 版本时,调整检查更新频率

如果必须使用 snapshot,可以调整 Gradle 如何检查这些依赖更新的频率。

避免复杂的脚本

Groovy 和 Kotlin DSL 的逻辑越简单,Gradle 花在解析和执行上的时间就越少。

持续分析和优化

使用 Gradle Profiler 和其他工具来分析构建性能瓶颈,并根据分析结果进行优化。

为 CI 管道配置特定的 Gradle 属性

在 CI/CD 管道中,特别配置的 Gradle 属性可以提高构建的稳定性和性能。

适当实施以上策略可以显著改善 Gradle 的构建速度和效率。在任何优化之前,最好确保测量当前的构建性能作为参考,之后再逐一实现可能的优化措施,并再次测量,以确保改动带来了正面效果。

5 Gradle 与 IDE 集成

5.1 讲述如何在各种 Java IDE 中使用 Gradle

Gradle 与多种 Java 集成开发环境(IDE)有良好的集成,使得开发者可以方便地在不同的开发环境中使用 Gradle 功能。以下是一些主要 Java IDEs 如何使用 Gradle 的概述:

IntelliJ IDEA

IntelliJ IDEA 对 Gradle 有原生支持,可以轻松导入 Gradle 项目、执行构建任务、运行测试和同步项目配置。

  1. 导入 Gradle 项目:使用 “Open” 或 “Import Project” 选项选择项目目录或 build.gradle 文件。
  2. 运行和调试:IntelliJ IDEA 在界面中显示所有 Gradle 任务,在 Gradle 工具窗口中选择任务并执行。
  3. 依赖管理:自动同步 IDE 类路径与 build.gradle 文件中的依赖配置。

Eclipse

Eclipse 使用 Buildship 插件来支持 Gradle 项目。

  1. 安装 Buildship 插件:可以通过 Eclipse Marketplace 自动安装。
  2. 导入和创建 Gradle 项目:可从欢迎屏幕或通过 “File” > “Import” 菜单选择 “Existing Gradle Project” 或 “Gradle Project”。
  3. 构建和运行:在 Gradle Tasks 视图中有任务列表供选择执行。

NetBeans

NetBeans 也支持 Gradle 集成,并展示了一个专门的 Gradle 项目视图。

  1. 安装 Gradle 插件:如果插件未预装,则需要手动安装。
  2. 导入项目:NetBeans 可以直接打开 build.gradle 文件或使用 “Open Project” 功能导入 Gradle 项目。
  3. 运行 Gradle 任务:使用项目上下文菜单中的 “Run”、“Debug” 和 “Test” 选项执行相应任务。

Visual Studio Code

Visual Studio Code(VS Code)是一个轻量级的代码编辑器,配备扩展插件后可支持 Gradle。

  1. 安装 Gradle 插件:通过 VS Code 的扩展市场安装 Gradle 插件,如 “Gradle for Java”。
  2. 导入项目:VS Code 可以通过插件提供的命令导入 Gradle 项目。
  3. 执行 Gradle 任务:插件提供的命令面板或侧边栏视图可用来运行 Gradle 任务。

在上述各个 IDE 中使用 Gradle 的共同点是,你只需关注 build.gradlesettings.gradle 文件来配置项目,IDE 会根据这些配置自动同步项目设置和依赖。开发者可以在 IDE 的图形界面中方便地执行和管理 Gradle 构建任务和依赖项,同时利用 IDE 提供的额外功能,如代码自动完成、重构、版本控制等。

5.2 解释 Android Studio 和 Gradle 的集成

Android Studio 是一个特定于 Android 的集成开发环境(IDE),它基于 IntelliJ IDEA 平台。它为 Android 应用开发提供了一系列强大的工具和功能,包括代码编辑器、模拟器、性能测试工具和一个强大的构建系统。Gradle 是 Android Studio 中使用的官方构建工具。

Android Studio 和 Gradle 集成的主要特点包括:

  1. 构建脚本:

    • 在 Android Studio 中,Gradle 构建脚本使用 Groovy 或 Kotlin DSL 来定义项目的构建逻辑。
    • build.gradle(项目级)和 build.gradle(模块级,如 app)是主要的构建配置文件,它们用于配置插件应用、依赖项、编译选项等。
  2. 自动化与自定义构建:

    • Gradle 使 Android 开发者能够执行自动化构建任务并自定义构建逻辑,例如,为不同的构建变体(比如测试和发布)执行不同的构建步骤。
    • 它支持多种构建变量和配置,如 debug 和 release。
  3. 依赖管理:

    • 使用 Gradle 仓库,如 Maven Central 和 JCenter,以及 Google Maven 仓库来管理项目依赖。
    • 通过声明式语法添加远程依赖和模块依赖。
  4. 多模块项目:

    • Android Studio 支持将应用拆分成多个模块,并使用 Gradle 来管理它们之间的依赖关系。
  5. 构建变体:

    • 定义不同的构建变体以满足特定的构建需求,如不同的版本或产品风味。
  6. 清洁架构:

    • Gradle 支持清洁架构的实践,允许分离业务逻辑、界面和数据库代码。
  7. 即时运行与应用程序部署:

    • Android Studio 结合 Gradle 提供了即时运行(Instant Run)等功能,可以更加迅速地将代码更新推送至运行中的应用或模拟器中。
  8. 增量构建:

    • Gradle 支持增量构建,这意味着只有发生变更的部分会被重新构建,从而加速了开发和测试过程。
  9. Gradle Wrapper:

    • 使用 Gradle Wrapper 确保所有开发人员都使用相同版本的 Gradle,这有助于避免不一致的构建结果。

配置 Android Studio 以使用 Gradle

  • 在新建或导入的项目中,Android Studio 会自动生成 Gradle 相关的配置文件和目录结构。
  • 提供了一系列可视化的工具和编辑器来编辑 Gradle 脚本,无需直接编辑文件,虽然高级用户仍然可以手动编辑它们以实现复杂的自定义逻辑。

同步依赖

  • 当依赖发生变化时,Android Studio 提供了“同步”选项,可以同步 Gradle 构建脚本与项目结构。

Android Studio 和 Gradle 的集成,为 Android 应用的开发提供了强大的工具和自动化支持,极大地提高了开发者的生产力。

5.3 讨论 Gradle Wrapper 的作用及其重要性

Gradle Wrapper 是一个重要的工具,它允许任何人使用项目预定义的 Gradle 版本进行构建,而无需预先安装 Gradle。这是通过将 Gradle Wrapper 配置为工程的一部分来实现的。以下是 Gradle Wrapper 的作用及其重要性的详细描述:

作用

1. 版本一致性

Gradle Wrapper 确保所有开发人员和构建环境(如持续集成服务器)都使用相同版本的 Gradle。这意味着自动使用正确的 Gradle 版本,无需手动同步。

2. 无需安装

对于新加入项目的开发者来说,无需担心安装及配置正确版本的 Gradle。只需通过 Wrapper 脚本即可自动下载并使用合适的 Gradle 版本。

3. 项目独立

每个项目可以使用其特定的 Gradle 版本而不影响其他项目。这样,升级或配置变更不会有全局效应,降低了升级或迁移的复杂性。

4. 安全引导

Gradle Wrapper 可以提供项目安全引导,因为它通过校验和验证来下载 Gradle 的正确版本。

如何使用

要启动 Gradle Wrapper,只需在项目中运行 gradlew(在 Unix-like 系统)或 gradlew.bat(在 Windows 系统)脚本即可。这些脚本位于项目的根目录中。

# Unix-like 系统
./gradlew build

# Windows 系统
gradlew.bat build

建立 Gradle Wrapper

使用以下命令生成或更新 Gradle Wrapper 文件和目录:

gradle wrapper --gradle-version X.Y --distribution-type all

这将创建或更新以下文件:

  • gradlewgradlew.bat 脚本文件。
  • gradle/wrapper/gradle-wrapper.properties 文件,其中包含了所需的 Gradle 版本和其下载来源。
  • gradle/wrapper/gradle-wrapper.jar 文件,这是可执行的 Wrapper 二进制文件。

一旦这些文件在版本控制中,任何人都可以使用这个预配置的 Gradle 环境来构建项目。

重要性

  • 提高项目的自包含能力:Gradle Wrapper 使得项目自包含所需的构建工具版本,从而提高了自我充足性。
  • 简化 CI/CD 流程:在持续集成和持续部署流程中使用 Gradle Wrapper,可以确保使用的是合适的构建工具,无需在 CI/CD 系统中管理 Gradle 版本。
  • 减少入门门槛:新团队成员可以更容易地开始贡献代码,因为构建过程起点的设置极为简单化。

Gradle Wrapper 是实现可重复构建的最简单和最有效的机制之一。对于依赖 Gradle 作为构建系统的项目来说,它已成为一种最佳实践。

6 Gradle 测试和代码质量

6.1 如何使用 Gradle 来执行自动化测试

使用 Gradle 执行自动化测试是一个有效的方式来确保你的代码质量,并防止未来的更改破坏现有功能。Gradle 提供了强大的测试框架集成,可以轻松设置并运行自动化测试。

以下是使用 Gradle 执行自动化测试的基本步骤:

1. 配置测试依赖

首先,在 build.gradle 文件中添加你所选择的测试框架作为依赖。例如,如果你使用 JUnit 作为你的测试框架,你可以按如下方式添加依赖:

dependencies {
    // 添加 JUnit 作为测试依赖
    testImplementation 'junit:junit:4.13.2'
}

如果是使用 JUnit 5,那么依赖的配置可能会略有不同,如下所示:

dependencies {
    // 添加 JUnit Jupiter API 和引擎作为测试依赖
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.1'
}

2. 编写测试代码

src/test/java 目录中编写你的测试类和方法。确保你的测试类名以 Tests 结尾,测试方法上添加了合适的测试注解。

例如:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

class MyTests {

    @Test
    void testSomething() {
        assertEquals(4, 2 + 2);
    }
}

3. 配置测试任务

Gradle 的 Java 插件提供了一个 test 任务来运行测试。你可以在 build.gradle 文件中配置 test 任务来自定义测试行为,例如设置系统属性、环境变量或并行运行:

test {
    useJUnitPlatform()
    maxParallelForks = 4

    systemProperty 'some.property', 'value'
    environment 'SOME_ENV', 'value'
    
    // Includes or excludes tests
    include '**/MyTests.class'
    exclude '**/IntegrationTests.class'
}

4. 执行测试

使用 Gradle 命令行工具来执行测试:

gradle test

这会编译和运行 test 目录下的所有测试类。

5. 查看测试报告

Gradle 在 build/reports/tests/test 目录下生成 HTML 测试报告。你可以在浏览器中打开这些 HTML 文件查看详细的测试结果。

6. 持续集成

在持续集成(CI)服务器上,配置任务来使用 Gradle 运行测试。通常这会与项目的自动化构建过程集成。

扩展测试配置

Gradle 提供了额外的配置和插件来支持更复杂的测试需求,如集成测试、功能测试和报告配置。例如,你可以创建一个自定义的 Gradle 任务来运行一个单独的测试套件。

通过使用 Gradle 来执行自动化测试,你可以保证代码在每次构建时都经过彻底的测试检验,从而提升应用程序的可信度和代码质量。

6.2 描述 Gradle 在代码质量管理中的应用

Gradle 在代码质量管理中可以集成多种工具和插件来执行代码分析、格式化检查、单元测试覆盖率跟踪等任务。这帮助开发者提高代码质量,维护代码的健壮性和可维护性。以下是一些在 Gradle 中常用于代码质量管理的插件和其应用:

1. Checkstyle 插件

  • 用途:Checkstyle 插件用于对 Java 源代码执行静态代码分析,确保代码符合定义的代码风格和标准。
  • 配置示例
apply plugin: 'checkstyle'

checkstyle {
    toolVersion = '8.41'
    config project.resources.text.fromURI('http://my.company.com/checkstyle.xml')
}

使用 checkstyle 任务可以执行代码风格检查。

2. PMD 插件

  • 用途:PMD 提供静态规则集来分析 Java 代码,识别潜在的代码问题,如未使用的变量、空的 try/catch 块、不必要的对象创建等。
  • 配置示例
apply plugin: 'pmd'

pmd {
    toolVersion = '6.34.0'
    // 额外的 PMD 配置
}

使用 pmd 任务可以执行代码质量检查。

3. SpotBugs 插件

  • 用途:SpotBugs 是 FindBugs 的继任者,它执行字节码静态分析来识别 Java 代码中的 BUG。
  • 配置示例
plugins {
    id 'com.github.spotbugs' version '4.7.0'
}

spotbugs {
    // 额外的 SpotBugs 配置
}

SpotBugs 插件可以通过 spotbugsMainspotbugsTest 任务对主要和测试代码进行分析。

4. JaCoCo 插件

  • 用途:JaCoCo 提供了代码覆盖率统计功能,可以对单元测试的覆盖率进行测量和报告。
  • 配置示例
apply plugin: 'jacoco'

jacoco {
    toolVersion = '0.8.7'
}

JaCoCo 会在每次测试运行后生成覆盖率报告。

5. SonarQube 插件

  • 用途:SonarQube 插件可以将 Gradle 项目与 SonarQube 服务器集成,提供连续的代码质量分析。
  • 配置示例
plugins {
    id 'org.sonarqube' version '3.3'
}

sonarqube {
    properties {
        property 'sonar.projectName', 'My Project'
        // 其他 SonarQube 属性
    }
}

通过 sonarqube 任务可以上传分析结果至 SonarQube 服务器。

集成这些插件

集成以上插件后,你可以通过一个统一的 Gradle 构建任务来执行所有代码质量检查。一些工程可能会有一个自定义的 quality 任务,它依赖于所有代码质量相关的任务:

task quality {
    dependsOn 'checkstyle', 'pmd', 'spotbugsMain', 'test', 'jacocoTestReport'
}

通过将代码质量管理自动化,Gradle 帮助团队确保代码持续符合质量标准,捕捉潜在的缺陷,并在生产环境出现问题前减少风险。在持续集成(CI)的环境中,这些任务通常在每次代码提交后自动运行,提供即时反馈。

6.3 讨论 Gradle 与 SonarQube 的集成

集成 Gradle 和 SonarQube 可以自动化地执行代码质量检测和分析,这是 modern CI/CD 管道中的一个重要步骤。通过 Gradle 处理 SonarQube 扫描允许项目在每次构建时自动执行静态代码分析,帮助开发团队检测潜在的问题和改进代码质量。

使用 SonarScanner for Gradle

SonarQube 提供了 SonarScanner for Gradle 插件用来在 Gradle 构建过程中启动和配置 SonarQube 分析。

步骤 1: 引入 SonarQube 插件

在你的项目的 build.gradle 文件中引入 SonarQube 插件:

plugins {
    id "org.sonarqube" version "3.3" // 使用最新版本
}
步骤 2: 配置 SonarQube 参数

build.gradle 中配置 SonarQube 的服务器参数和其他有关项目的属性。

sonarqube {
    properties {
        property 'sonar.projectName', 'My Project'
        property 'sonar.projectKey', 'org.mycompany.myproject'
        property 'sonar.host.url', 'http://your-sonarqube-server.com'
        property 'sonar.login', 'sonarqube-token' // 使用Token进行鉴权,建议通过环境变量或其他安全方式注入
        // 其他属性...
    }
}
步骤 3: 运行 SonarQube 分析

要开始一个 SonarQube 分析,你可以在命令行中使用 Gradle 任务:

gradle sonarqube

这个命令将会启动 SonarQube 扫描,并将结果发送到 SonarQube 服务器。

步骤 4: 检查分析结果

分析完成后,你可以在 SonarQube 服务器的 UI 中检查结果,包括代码覆盖率、缺陷、代码异味和技术债务。

最佳实践

  • 在 CI/CD 管道配置中包含 SonarQube 分析,确保每次提交或定期都有代码分析的执行。
  • 在本地开发流程中也包含 SonarQube 扫描任务,以便开发者在提交代码前能及时发现问题。
  • 适当地配置 SonarQube 规则,以确保它符合团队的代码质量标准和实践。
  • 使用 SonarQube 分支和 Pull Request 分析功能来跟踪特性分支的代码质量。
  • 使用合适的 SonarQube 插件以支持更多的编程语言和代码分析功能。
  • 保护 SonarQube 服务器的访问,特别是 SonarQube 分析令牌和配置。

集成 Gradle 和 SonarQube 使开发团队能够构建起主动代码质量改进的流程,并促进质量保证的自动化。这种集成还加速了发现和修复潜在缺陷、提升软件可维护性和安全性的过程。

7 Gradle 连续集成和部署

7.1 讲述 Gradle 在 CI/CD 系统中的应用

Gradle 在持续集成/持续交付(CI/CD)中的应用是基于其自动化构建和测试能力的。CI/CD 系统通过自动化的软件交付流程,能够使团队快速、可靠地构建、测试和发布软件。Gradle 通过为这个过程提供一致性和高效性,成为其中的关键工具之一。

在 CI 系统中的应用

CI(持续集成)系统自动化合并开发者的变更到主仓库,然后构建应用并运行测试,确保这些变更没有破坏任何东西。Gradle 在 CI 中的应用包括:

  1. 自动化构建:Gradle 提供了构建脚本的执行,可以处理依赖下载、编译、打包、测试等任务。
  2. 构建标准化:无论是在开发者的本地环境还是在 CI 服务器上,Gradle 保证构建过程的一致性与可重复性。
  3. 测试自动化:通过 Gradle 运行单元测试、集成测试和其他质量检查,然后生成测试报告。

在 CD 系统中的应用

CD(持续交付或持续部署)是持续集成的扩展,它不仅自动化测试,也自动化应用的发布过程。Gradle 在 CD 中的应用包括:

  1. 构建工件:Gradle 负责生成可部署的工件,如 JAR、WAR、EAR 文件或 Docker 镜像。
  2. 部署准备:Gradle 可以执行为部署到生产环境或测试环境准备工件的任务,如应用数据库迁移、配置环境变量等。
  3. 构建管道:Gradle 的 Build Scans 或者 Gradle Enterprise 可以为 CD 提供详细的构建控制和分析,实现构建管道的优化。

集成到 CI/CD 工具

Gradle 可以很容易地与 Jenkins、GitLab CI、Travis CI、CircleCI、TeamCity、Bamboo 等流行的 CI/CD 工具集成。集成通常包括以下步骤:

  1. 配置构建脚本:使用 Gradle 创建构建文件,确保在本地执行无误。
  2. 集成到 CI/CD 服务器:CI/CD 服务器中的项目配置要包括 Gradle 的构建步骤,例如设置 Gradle 任务或者调用 gradlew 的命令。
  3. 提供构建环境:CI/CD 环境需要配置好 Gradle 构建所需的 JDK、环境变量和任何特定的 Gradle 配置。

使用 Gradle Wrapper

为了更好地维护构建的一致性和系统的独立性,通常会使用 Gradle Wrapper,这样不需要预先在 CI/CD 系统上安装 Gradle,也能保证团队成员使用相同版本的 Gradle。

通过这些机制,Gradle 成为自动化构建、测试和部署软件的可靠选择,有助于缩短交付周期,提升软件交付流程的质量和速度。在 DevOps 实践中,Gradle 的这些特性使其成为 CI/CD 管道的重要组成部分。

7.2 描述 Gradle 与 Jenkins 的集成

Gradle 与 Jenkins 的集成提供了强大的自动构建和部署能力。通过在 Jenkins 中配置 Gradle 构建任务,你可以自动化执行构建、测试、打包和部署 Android 应用或其他基于 Gradle 的项目。以下是集成 Gradle 的主要步骤:

1. 安装 Gradle 插件

为了使 Jenkins 与 Gradle 集成,首先需要在 Jenkins 上安装 Gradle 插件:

  • 登录 Jenkins 控制台。
  • 导航到 “系统管理 > 插件管理”。
  • 在 “可用” 标签页中查找 “Gradle Plugin” 并安装。

2. 配置 Gradle 环境

配置 Jenkins 构建节点上的 Gradle 环境:

  • 在 Jenkins 系统配置或全局工具配置中,配置一个或多个 Gradle 安装。可以选择安装时让 Jenkins 自动下载 Gradle,或者直接指定已安装的 Gradle 本地路径。
  • 有了 Gradle 环境之后,你可以在 Jenkins 任务中引用它。

3. 创建 Jenkins 任务

创建一个新的 Jenkins 任务(或作业)来执行 Gradle 构建:

  • 新建一个 Jenkins 项目并选择合适的类型(如 “自由风格的软件项目”)。
  • 在 “构建” 部分,添加 “调用 Gradle 脚本” 步骤。
  • 指定 Gradle 任务和其他构建参数。例如,你可能会运行 clean buildassembleRelease 等 Gradle 命令。

4. 配置源代码管理

在项目配置中,设置源代码管理,例如 Git 或 Subversion。输入仓库的 URL 和认证信息。

5. 配置构建触发器

配置构建触发器来确定何时执行 Gradle 构建任务。例如,你可以配置 “SCM 轮询” 或监听 Git 仓库的 Webhooks 来触发构建。

6. 添加构建步骤

在 “构建步骤” 中配置具体的 Gradle 命令,包括任务(task)和选项(如 -Pprofile=test)。

7. 执行 Gradle 脚本

  • Jenkins 将根据配置执行 Gradle 脚本,并显示构建日志。
  • 如果测试、代码分析或文档生成等步骤包含在 Gradle 脚本中为 Gradle 任务,则这些步骤也会被执行。

8. 设置后期构建动作

在构建成功后配置 Jenkins 执行的后续步骤,如通知开发者、部署到环境等。

9. 日志记录与结果

Jenkins 会记录 Gradle 构建的每一步并提供日志供审查。如果有测试步骤,还可以配置 Jenkins 收集并显示测试结果。

10. 保存并运行构建

保存 Jenkins 作业配置后,你可以手动触发构建或等待触发器自动执行。

使用 Jenkins 集成的 Gradle 能高效地执行构建脚本,并充分利用 Jenkins 的持续集成和持续部署功能。

7.3 解释 Gradle 的构建发布和部署策略

Gradle 是一个高度灵活的构建工具,用于自动化 Java、Groovy 和其他编程语言的构建、测试和部署过程。以下是 Gradle 的构建、发布和部署策略的基本概念:

构建发布

1. 生成构件

Gradle 使用 build.gradle 文件中的 build 任务来编译源代码并生成可执行构件,如 JAR、WAR 或 EAR 文件。

2. 构建流水线

Gradle 支持定义自定义任务和依赖关系,可以创建复杂的构建流水线,包括编译、单元测试、集成测试、代码质量检查、打包等阶段。

3. 版本控制

Gradle 允许使用插件来管理版本号并生成版本记录,如使用 maven-publishivy-publish 插件将构件发布到远程仓库。

4. 多环境构建

通过 Gradle 的配置系统,可以为不同环境(如开发、测试、生产等)定制构建过程,包括特定的配置参数和环境变量。

5. 构建缓存

Gradle 的构建缓存机制使得重用上一次构建的结果成为可能,大幅缩短了构建时间。

发布策略

1. 本地和远程存储

Gradle 可以将构件发布到本地 Maven 或 Ivy 存储,也可以发布到远程仓库,如 Artifactory、Nexus 或 Maven 中央存储。

2. Snapshot 和 Release

Gradle 可以配置来处理 Snapshot 版本(开发中的版本)和 Release 版本(正式发布的稳定版本)的生成和发布。

3. 签名构件

为了确保构件安全,Gradle 支持对其进行 GPG 签名后再进行发布。

4. 持续集成

通过与 Jenkins、Travis CI、CircleCI 等持续集成服务的集成,每次提交后自动构建和发布构件。

部署策略

1. 自动部署

可以通过 Gradle 插件或脚本自动将应用部署到服务器或容器化平台,如 Docker、Kubernetes 等。

2. 基础设施即代码(IaC)

利用 Gradle 和 Terraform、Ansible 等工具结合,可以将基础设施的搭建和应用部署整合到一个流程中。

3. 配置管理

使用 Gradle 中的 configurations 配置来管理构件的依赖,并应用于不同的部署环境。

4. 应用平台集成

Gradle 有能力集成到应用平台,如 Cloud Foundry 或 Heroku,直接在 Gradle 流水线中实现从构建到部署的全过程。

要理解和应用 Gradle 的构建发布和部署策略,关键是要熟悉 build.gradle 配置文件以及 Gradle 插件生态,这让 Gradle 变得非常强大并且适应性很强。通过 Gradle,开发者可以实现高度自动化和定制化的构建和部署流程。

8 Gradle 安全和认证

8.1 讨论 Gradle 的认证和授权管理

Gradle 本身并不直接提供认证和授权管理机制,而是依赖于构建脚本中配置的外部资源和存储库来管理权限,如 Maven 仓库或私有仓库等。当需要从这些受保护的资源下载依赖或上传构建产物时,Gradle 必须配置相应的认证信息来授权操作。

以下是在 Gradle 中进行认证和授权管理的一些方法:

使用凭证配置仓库

在 Gradle 构建脚本中,你可以配置仓库的访问使用凭证认证,如用户名和密码。对于存储库的声明通常在 build.gradle 中的 repositories 部分进行:

repositories {
    maven {
        url 'https://private-repo.example.com/'
        credentials {
            username 'repo_user'
            password 'repo_password'
        }
    }
}

从环境变量中获取凭证

为了增强安全性,建议不要在构建脚本中硬编码敏感信息。取而代之的是,可以从环境变量或系统属性中动态获取:

repositories {
    maven {
        url 'https://private-repo.example.com/'
        credentials {
            username System.getenv('REPO_USER') ?: 'default_user'
            password System.getenv('REPO_PASSWORD') ?: 'default_password'
        }
    }
}

使用 Properties 文件

你也可以将凭证存储在本地的 .gradle/gradle.properties 文件中(不应提交到版本控制系统中),然后在 build.gradle 文件中引用这些属性:

repositories {
    maven {
        url 'https://private-repo.example.com/'
        credentials {
            username project.findProperty('repoUser') ?: 'default_user'
            password project.findProperty('repoPassword') ?: 'default_password'
        }
    }
}

然后,在 gradle.properties 文件中设置:

repoUser=actual_user
repoPassword=actual_password

使用认证插件

对于更高级的认证要求,比如 OAuth 或基于Token的认证,可以使用第三方插件或编写自定义的认证插件。例如,一些插件允许使用 API 密钥进行身份验证。

CI/CD 环境中的安全准则

在连续集成(CI)环境中执行 Gradle 构建时,通常会在 CI 系统中配置凭据。例如,在 Jenkins 中,可以使用 Credentials 插件管理敏感信息,并在构建过程中将凭证传递给 Gradle。

注意事项

  • 保密:确保不要在公共版本控制中暴露凭证,特别是在 build.gradlegradle.properties 文件等。
  • 权限最小化:尽量限制存储库用户权限到所需的最小范围内,例如,发布构建仅需要上传权限,不需要额外的写权限。
  • 定期轮换凭证:定期更换仓库用户的密码,并在凭证泄露时立即进行处理。

通过这些方法,Gradle 在与外部服务的交互中可以安全地进行认证和授权,从而保证了构建过程中的安全性和数据的保密性。

8.2 描述 Gradle 加密技术和最佳实践

在 Gradle 构建过程中处理敏感数据时,应使用加密技术来保护这些数据。以下是一些 Gradle 加密技术和最佳实践:

避免硬编码敏感数据

永远不要在 build.gradle 或其他 Gradle 脚本文件中硬编码敏感信息,如密码、密钥等。硬编码的值可能会不经意间暴露给源代码管理系统,并被提交到版本历史中。

使用环境变量

将敏感数据存储在环境变量中,并在 Gradle 脚本中动态读取它们:

def someApiKey = System.getenv('SOME_API_KEY')

你可以在 CI/CD 系统或本地开发环境的配置文件中设置这些环境变量。

使用 Gradle 属性

Gradle 属性(位于 gradle.properties 文件)可以用来存储用户相关的配置,并配合环境变量一起使用。此文件通常不应当被包含在源码管理中:

# 在 ~/.gradle/gradle.properties 中
someApiSecret=VALUE

然后,在构建脚本中引用这些属性:

def someApiSecret = project.hasProperty('someApiSecret') ? project.getProperty('someApiSecret') : System.getenv('SOME_API_SECRET')

加密插件

使用 Gradle 插件来保护敏感数据,并使这些数据在构建过程中得到解密。例如,插件 Credentials Plugin 可以帮助你使用加密的方法来安全地管理敏感数据。

密钥管理服务

对于企业项目,可以使用密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager、Azure Key Vault 等)来安全地存储、管理并在运行时检索敏感数据。

CI/CD 系统集成

如果使用持续集成 (CI) 工具(如 Jenkins、CircleCI、GitHub Actions 等),最佳实践是利用这些工具提供的密钥和凭据管理机制。

审计和强化安全性

定期审计你的 Gradle 构建配置及环境设置,验证没有敏感信息泄露并且所有配置都符合安全最佳实践。

通过遵循以上最佳实践,你可以提高 Gradle 构建过程中敏感数据的保障措施,避免在不安全的环境中暴露关键信息,从而降低安全风险。安全意识以及合理的加密和密钥管理策略应成为开发和 DevOps 团队工作的核心部分。

8.3 讲述如何保护 Gradle 构建的安全性

保护 Gradle 构建的安全性对确保整个软件开发生命周期(SDLC)的安全非常关键。以下是一些保护 Gradle 构建安全性的最佳实践:

1. 使用 HTTPS

确保下载依赖或与存储库交互时使用 HTTPS 而不是 HTTP,这将防止中间人攻击,确保传输的数据安全性。

repositories {
    maven {
        url 'https://your.secure.repo/url'
    }
}

2. 锁定依赖版本

build.gradle 文件中明确指定依赖版本,避免使用动态版本号,以防止意外使用恶意或不稳定的依赖版本。

dependencies {
    implementation 'com.example:my-dependency:1.2.3'
}

3. 管理和存放敏感数据

永远不要在构建脚本或版本控制系统中硬编码敏感信息,如密码或凭证。可以使用环境变量、Gradle 属性或安全管理服务来管理敏感数据。

password = System.getenv("MY_SECRET")

4. 使用认证

当从私有存储库下载依赖时,确保使用基本认证、令牌认证或其他安全机制。

5. 签名和验证构建输出

对你的构建成果(例如 JAR 或 APK 文件)进行数字签名,确保它们在发布过程中没有被篡改。

6. 权限控制

尽量遵循最小权限原则,限制 Gradle 脚本的权限,例如不能对系统进行未经限制的访问。

7. 使用依赖签名

使用 GPG 或其他工具验证依赖的签名,以确保它们是从可信来源获取的。

8. 审计和升级依赖性

定期审计项目依赖,删除不再使用的库,并保持依赖性最新,特别是对安全更新进行必要的升级。

9. 使用 Gradle 守护进程和构建缓存

Gradle 守护进程有助于加速构建,同时构建缓存可以跨多个构建重复使用未更改的输出,减少重复工作并保持构建速度。

10. 检查安全漏洞

利用像 OWASP Dependency-Check 这样的工具来检测项目依赖中的已知安全漏洞。

11. 利用 CI/CD 环境

在一个受控的 CI/CD 环境中运行 Gradle 构建,这通常提供了额外的安全措施和访问控制。

stages:
  - build
  - scan
  - deploy

12. 监控和日志记录

启用详细的构建日志记录和监控,以便在出现安全问题时追踪和调查。

通过遵循上述实践,您可以有效地保障 Gradle 构建过程的安全性,减少安全漏洞的风险,并提高整个构建过程的可信度。此外,使用专业的工具可以进一步强化构建安全性,如 SonarQube、Snyk、Nexus IQ 等。

9 Gradle 故障诊断和优化

9.1 解释 Gradle 构建缓存和实施策略

Gradle 构建缓存是一种减少构建时间和提高效率的机制,它可以捕捉任务输出并在未来的构建中重用这些输出。当任务的输入和依赖项保持不变时,构建缓存可以直接复用以前构建的结果,避免重复执行构建任务。以下是 Gradle 构建缓存的关键点和实施策略的解释:

关键点

  1. 本地构建缓存
    每个 Gradle 用户在本地机器上有一个构建缓存,它存储了此用户构建任务的输出。这可以在多次构建之间重用结果,尤其是在短期内频繁构建时。

  2. 远程构建缓存
    远程构建缓存适用于团队或持续集成环境,构建结果可以跨不同机器共享,使得团队成员或 CI 系统的每次构建都能受益于已缓存的过去构建结果。

  3. 可缓存任务
    并不是所有任务都适合缓存。为了让任务结果能够被缓存,任务必须是确定性的,并且它的输出不能依赖于外部环境。

实施策略

  1. 使任务适用于缓存

    • 避免在任务中使用不确定的或依赖环境的输入。
    • 确保任务的输出不受环境影响,如不应该包含绝对路径等。
  2. 开启构建缓存

    • gradle.properties 文件中启用本地缓存,添加以下配置:

      org.gradle.caching=true
      
    • 配置 Gradle Wrapper 或 CI 服务器以利用远程构建缓存。

  3. 优化构建逻辑

    • 重构构建逻辑,以便于更好地利用缓存,例如,避免在构建脚本中使用动态生成的版本号。
  4. 目录管理

    • 保持构建目录干净有序,以防错过缓存机会。
  5. 监控缓存行为

    • 使用 Gradle 的 Build Scan 或其他分析工具来监控和优化缓存的使用。
  6. 远程缓存服务器

    • 如果使用远端缓存,考虑使用 Gradle Enterprise 或设置兼容的缓存服务器,如 HTTP 服务器或者特定的插件提供的解决方案。
  7. 进行命中率分析

    • 分析构建缓存命中率,以识别未命中缓存的原因。
  8. 维护和清理构建缓存

    • 定期维护和清理远程缓存内容,避免过时或不再需要的任务输出占用空间。

通过以上策略,Gradle 的构建缓存能够有效缩短构建时间,特别是对于大型项目来说,这项功能在减少 CI/CD 周期、加速开发流程中扮演着重要角色。

9.2 讨论 Gradle 构建故障的诊断和修复方法

当使用 Gradle 构建项目时,可能会遇到各种故障和问题。以下是一些常见的诊断和修复 Gradle 构建问题的方法:

1. 使用 --stacktrace 选项

  • 当构建失败时,添加 --stacktrace 参数运行 Gradle 任务可以提供详细的错误信息和异常堆栈跟踪,帮助定位问题源头。

    ./gradlew build --stacktrace
    

2. 使用 --info--debug 选项

  • --info 提供更多构建过程中的信息,而 --debug 提供详细的调试输出,这些可以揭示构建过程中的更多细节。

    ./gradlew build --info
    ./gradlew build --debug
    

3. 检查依赖冲突

  • 若出现依赖相关的问题,使用 dependencies 任务可以帮助你理解项目的依赖树并发现冲突。

    ./gradlew :module:dependencies
    

4. 结合 IDE 功能

  • 大多数现代 IDE 如 IntelliJ IDEA 和 Android Studio 提供了集成的 Gradle 支持。他们通常会提供有关构建错误的详细诊断信息,并可能提供一些快速修复方案。

5. 使用 Gradle 构建扫描

  • Gradle Enterprise 或其他构建扫描工具提供了构建分析的功能。它可以帮助你理解构建性能瓶颈和失败的具体原因。

6. 检查 Gradle 配置

  • 仔细审查 build.gradle 脚本以及项目和模块级的其他配置文件。确认所有插件和依赖的版本都是正确的,并且配置设置合理。

7. 清理和重新构建

  • 有时候,清除缓存和重建项目可以解决一些难以诊断的问题。

    ./gradlew clean build
    

8. 查阅文档和社区

  • 查看官方文档来理解错误信息,搜索社区和论坛看看别人是否有相同的问题以及如何解决。

9. 更新 Gradle 版本

  • 使用当前稳定版本的 Gradle 和所有插件。老旧的版本可能包含已知的问题。

10. 分离和简化构建逻辑

  • 将复杂的构建逻辑拆分成小的可管理的部分。这不仅有助于理解问题所在,也会让构建过程更为稳定可靠。

11. 环境检查

  • 检查构建环境是否恰当。确保本地环境和持续集成服务器上的设置一致,如环境变量、Java 版本等。

12. 本地与 CI/CD 环境对比

  • 如果在 CI/CD 系统中构建失败而在本地构建成功,比较两个环境中的差异可能有助于发现问题所在。

记住:诊断和修复构建问题是一个逐步排除的过程。在修复问题时,尽量尝试最小的改动集,这样可以更容易地识别导致问题的特定变更。

9.3 描述 Gradle 构建速度的优化策略

为了优化 Gradle 构建速度,你可以采取多种策略来提高效率和缩短构建时间。以下是一些常用的 Gradle 构建速度优化策略:

1. 启用构建缓存

Gradle 构建缓存可以跨不同构建重用已生成的输出,从而减少执行时间。为了启用构建缓存,可以在 gradle.properties 文件中添加以下设置:

org.gradle.caching=true

2. 配置守护进程

Gradle 守护进程能够加快构建速度,因为它保持着构建信息的热身状态。通常情况下,Gradle 守护进程是默认启用的,如果需要特别配置或优化它,同样可以修改 gradle.properties

org.gradle.daemon=true

3. 配置并行执行

Gradle 支持并行构建,它会同时执行多个项目的独立任务,这可以显著加快多项目构建的速度。在 gradle.properties 中配置并行执行:

org.gradle.parallel=true

4. 优化内存配置

分配给 Gradle VM 的内存越多,构建速度通常越快。 gradle.properties 中可以设置 Gradle 的最小堆大小和最大堆大小:

org.gradle.jvmargs=-Xmx4g -Xms1g -XX:MaxMetaspaceSize=1g

请根据你的机器具体能力适当设置内存。

5. 使用宽泛的依赖版本

尽量避免使用动态依赖版本(例如 1.+),因为动态版本需要 Gradle 在构建时检查新版本,这可能增加解析依赖的时间。

6. 最小化项目依赖

减少不必要的项目依赖、插件和任务可以降低 Gradle 的工作负担,提高构建速度。定期检查项目依赖,去除未使用或重复的。

7. 使用低延迟的网络

确保 Gradle 使用的网络连接到 Maven Central 和其他仓库有足够的带宽和低延迟。

8. 构建脚本性能

编写高效的构建脚本,确保任务输入和输出明确,在构建脚本中避免复杂的逻辑。

9. 优化任务执行

使用 --profile 或 Gradle 的构建扫描功能来识别慢任务,并尝试优化或重写这些任务。

10. 选择性执行任务

使用 Gradle 任务的选择性执行来避免执行不必要的任务。例如,如果只更改了应用内的代码,不需要重新运行静态代码分析。

11. 持续集成优化

持续集成服务器上,确保使用 Gradle Wrapper,工作目录保持一致,避免磁盘I/O和资源争用问题。

这些优化策略在组合使用时会使 Gradle 构建速度得到显著提升。然而,优化过程是一个持续的探索和调整的过程,需要不断地评审构建过程并实施相应改进。

  • 26
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

golove666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值