当前位置:   article > 正文

Gradle入门

Gradle入门

Gradle入门


学习Gradle最好的方法是从官网学习, 本篇只是从官网截取片段,只能了解大概,所以希望学习时遇到所有不了解的词汇都能去搜索查找。
官网: https://gradle.org/

官方文档: https://docs.gradle.org/current/userguide/


Gradle简介

Gradle 是一款开源的组建自动化工具,其设计灵活性足以构建几乎任何类型的软件。以下是对其一些最重要特点的高级别概述:

  • High performance 高性能

    Gradle 通过仅仅运行那些因为输入或输出发生变化而需要运行的任务来避免不必要的工作。还可以使用生成缓存来支持重用以前运行的任务输出,甚至可以重用来自不同计算机的任务输出(使用共享生成缓存)。

  • JVM foundation JVM 基金会

    Gradle 运行在 JVM 上,你必须安装一个 JDK (JDK)才能使用它

  • Conventions 约定

    Gradle 借鉴了 Maven 的经验,使得常见类型的项目(比如 Java 项目)很容易通过实现约定来构建

  • Extensibility 可扩展性

    您可以很容易地扩展 Gradle 来提供您自己的任务类型,甚至构建模型。

  • IDEA support IDEA支持

    几个主要的 IDE 允许您导入 Gradle 构建并与它们交互: Android Studio、 IntelliJ IDEA、 Eclipse 和 NetBeans。Gradle 还支持生成将项目加载到 VisualStudio 中所需的解决方案文件。

  • Insight 洞察力

    生成扫描提供了有关生成运行的大量信息,您可以使用这些信息来识别生成问题。它们尤其擅长帮助您识别构建性能方面的问题。您还可以与其他人共享构建扫描,如果您需要征求修复构建问题的建议,这尤其有用。


关于Gradle你要知道的五件事

  1. Gradle 是一个通用的构建工具

  2. 核心模型以任务为基础

  3. 级别有几个固定的构建阶段

    1. 初始化

    2. 配置

    3. 执行

    这些阶段形成了 Gradle 的构建生命周期。

    设计良好的构建脚本主要由声明性配置而不是命令式逻辑组成。

  4. 分级可扩展的方式不止一种

    Gradle 提供了几种允许您扩展它的机制,例如:

    1. 自定义任务类型。
    2. 自定义任务操作。
    3. 项目和任务的额外属性。
    4. 定制会议。
    5. 一个定制的模型。
  5. 构建脚本针对 API 进行操作


兼容性说明

Java 版本第一个支持的版本
82.0
94.3
104.7
115.0
125.4
136.0
146.3
156.7
167.0
177.3
187.5

安装

条件

对应版本的JDK

使用包管理器安装

SDKMAN! 是在大多数基于 Unix 的系统上管理多个软件开发工具包的并行版本的工具。

sdk install gradle 7.5.1
  • 1

Homebrew是"macOS 缺失的包管理器"。

brew install gradle
  • 1

手动安装

下载最新的发行版
https://gradle.org/releases


升级Gradle

./gradlew wrapper --gradle-version=7.5.1 --distribution-type=bin
  • 1

快速开始构建 Java Application示例

创建并进入一个项目目录demo,输入:

gradle init
  • 1

依次选择需要构建项目特性选项。
构建完成的java application项目有如下目录结构:

├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── app
├── build.gradle
└── src
├── main
│   └── java
│       └── demo
│           └── App.java
└── test
└── java
└── demo
└── AppTest.java
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

项目文件

settings.gradle文件

rootProject.name = 'demo'
include('app')
  • 1
  • 2

rootProject.name 为构建指定一个名称,这会覆盖默认行为,即根据构建所在的目录来命名构建。建议设置一个固定的名称,因为如果项目被共享,文件夹可能会发生变化——例如,作为 Git 存储库的根目录。

include ("app")定义构建由一个名为 app 的子项目组成,该子项目包含实际的代码和构建逻辑。可以通过附加 include (...)语句添加更多子项目。

app/build.gradle(.kts)文件

plugins {
    id 'application' //1
}
repositories {
    mavenCentral() //2
}
dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'  
    implementation 'com.google.guava:guava:31.0.1-jre'  //3
}

application {
    mainClass = 'demo.App' //4
}

tasks.named('test') {
    useJUnitPlatform()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  1. 应用application插件来增加对在 Java 中构建 CLI 应用程序的支持。
  2. 使用 Maven Central 解析依赖关系。
  3. 使用 JUnit Jupiter 进行测试
  4. 此依赖项由应用程序使用。
  5. 定义应用程序的主类。

运行应用程序

$ ./gradlew run

> Task :app:run
Hello world!

BUILD SUCCESSFUL
2 actionable tasks: 2 executed
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

打包应用

$ ./gradlew build

BUILD SUCCESSFUL in 0s
7 actionable tasks: 7 executed
  • 1
  • 2
  • 3
  • 4

发布构建扫描

$ ./gradlew build --scan

BUILD SUCCESSFUL in 0s
7 actionable tasks: 7 executed

Publishing a build scan to scans.gradle.com requires accepting the Gradle Terms of Service defined at https://gradle.com/terms-of-service.
Do you accept these terms? [yes, no] yes

Gradle Terms of Service accepted.

Publishing build scan...
https://gradle.com/s/5u4w3gxeurtd2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

构建

参考: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html

最好了解Groovy或Kotlin一种语言

如果只想把Gradle当作maven, 这一章可以随机跳过, 尤其是构建脚本片段


构建生命周期

Gradle 的核心是一种基于依赖关系的编程语言。在 Gradle,这意味着您可以定义任务和任务之间的依赖关系。Gradle 保证这些任务按照其依赖项的顺序执行,并且每个任务只执行一次。


设置文件

设置文件在初始化阶段执行。多项目构建必须在多项目层次结构的根项目中有一个 settings.gradle 文件。之所以需要它,是因为设置文件定义了哪些项目正在参与多项目生成(请参见创作多项目生成)。对于单项目生成,设置文件是可选的。

设置文件由 Gradle 通过一个变数命名原则来确定。这个文件的默认名称是 setings.gradle

setings.gradle配置: https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html


构建阶段

一个 Gradle 构建有三个不同的阶段。

  • 初始化阶段

    Gradle 支持单个和多个项目的构建。在初始化阶段,Gradle 确定哪些项目将参与构建,并为每个项目创建一个 Project 实例。

    Gradle 如何知道是否进行单个项目构建或多个项目构建?

    • 它在父目录中查找 settings.gradle
    • 如果未找到,则将生成作为单个项目生成执行。
    • 如果找到了 settings.gradle 文件,Gradle 将检查当前项目是否属于在已找到的 settings.gradle 文件中定义的多项目层次结构的一部分。否则,生成将作为单个项目生成执行。否则将执行多项目构建。

    Gradle 为参与构建的每个项目创建一个 Project 对象。

  • 配置阶段

    在此阶段配置项目对象。执行所有构建项目的构建脚本。

    构建脚本可以随着构建在其生命周期中的进展而接收通知。这些通知通常采用两种形式: 您可以实现特定的侦听器接口,或者您可以提供一个闭包,以便在触发通知时执行。

  • 执行阶段

    Gradle 确定要执行的任务的子集,这些任务是在配置阶段创建和配置的。子集由传递给 gradle 命令和工作目录的任务名参数决定。然后,Gradle 执行所选择的每个任务。


构建脚本基础

项目(projects), 插件(plugins)和任务(tasks)

每个 Gradle 构建都由一个或多个项目组成。一个项目代表什么取决于你使用 Gradle 做什么。例如,一个项目可能表示一个库 JAR 或一个 Web 应用程序。它可能表示由其他项目生成的 JAR 组装而成的发行版 ZIP。项目不一定代表要构建的事物。它可能表示要完成的事情,比如将应用程序部署到临时环境或生产环境。

Gradle 在一个项目上能做的工作是由一个或多个任务决定的。任务表示构建执行的某个原子工作。这可能是编译一些类、创建一个 JAR、生成 Javadoc 或将一些归档发布到存储库。

通常,任务是通过应用插件提供的,这样您就不必自己定义它们。

Gradle 的构建脚本可以使用 Groovy 和 Kotlin(略) 的全部功能(需要你了解Groovy和Kotlin)

在 Gradle 的任务中使用 Groovy

build.gradle

tasks.register('upper') {
    doLast {
        //定义字符串
        String someString = 'mY_nAmE'
        //输出
        println "Original: $someString"
        println "Upper case: ${someString.toUpperCase()}"
        //使用循环
        4.times { print "$it " }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用 gradle -q upper 执行构建脚本

> gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
0 1 2 3 
  • 1
  • 2
  • 3
  • 4

任务(task)依赖

您可以声明依赖于其他任务的任务。

build.gradle

tasks.register('hello') {
    doLast {
        println 'Hello world!'
    }
}
tasks.register('intro') {
    dependsOn tasks.hello
    doLast {
        println "I'm Gradle"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

执行构建脚本 :

> gradle -q intro
Hello world!
I'm Gradle
  • 1
  • 2
  • 3

灵活注册任务

可以使用它在循环中注册同一类型的多个任务。

build.gradle

4.times { counter ->
    tasks.register("task$counter") {
        doLast {
            println "I'm task number $counter"
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

操纵现有任务

通过 API 访问任务-添加依赖项

build.gradle

4.times { counter ->
    tasks.register("task$counter") {
        doLast {
            println "I'm task number $counter"
        }
    }
}
tasks.named('task0') { dependsOn('task2', 'task3') }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

通过 API 添加行为访问任务

build.gradle

tasks.register('hello') {
    doLast {
        println 'Hello Earth'
    }
}
tasks.named('hello') {
    doFirst {
        println 'Hello Venus'
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用方法

build.gradle

tasks.register('loadfile') {
    doLast {
        fileList('./antLoadfileResources').each { File file ->
            ant.loadfile(srcFile: file, property: file.name)
            println "I'm fond of $file.name"
        }
    }
}

File[] fileList(String dir) {
    file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

默认任务

Gradle 允许您定义一个或多个默认任务,如果没有指定其他任务,则执行这些任务。

build.gradle

defaultTasks 'clean', 'run'

tasks.register('clean') {
    doLast {
        println 'Default Cleaning!'
    }
}

tasks.register('run') {
    doLast {
        println 'Default Running!'
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

为构建脚本声明外部依赖项

具有外部依赖关系的构建脚本

build.gradle

import org.apache.commons.codec.binary.Base64

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
    }
}

tasks.register('encode') {
    doLast {
        def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
        println new String(encodedString)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Gradle插件

Gradle插件集合: https://plugins.gradle.org/


所有有用的特性,编译 Java 代码的能力,都是通过插件添加的。插件可以添加新的任务(例如 JavaCompile, 编译 Java 源文件) ,域对象(例如 SourceSet,用于表示 Java 源文件和资源文件) ,约定(例如 Java 源位于 src/main/Java) ,以及从其他插件扩展核心对象和对象。

plugins {
    id 'java'
}
tasks.withType(JavaCompile) {
    //启用在单独的守护进程中编译
    options.fork = true
}
sourceSets {
  main {
    java {
      //排除目录
      exclude 'some/unwanted/package/**'
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

插件类型

  • 二进制插件

    二进制插件要么通过实现插件接口以编程方式编写,要么使用 Gradle 的一种 DSL 语言以声明方式编写。二进制插件可以驻留在构建脚本中、项目层次结构中或者外部的插件 jar 中。

  • 脚本插件

    脚本插件是进一步配置构建的附加构建脚本,通常实现一种声明性方法来操作构建。它们通常在构建中使用,尽管可以从远程位置对它们进行外部化和访问。


使用插件

使用插件实际上意味着在你想用插件增强的项目上执行插件的 Plugin.application (T)。应用插件是幂等的。也就是说,您可以安全地多次应用任何插件,而不会产生副作用。

plugins{}块目前只能在项目的build.gradlesettings.gradle 文件中使用

你可以通过插件 id 来应用插件,这是插件的全局唯一标识符或者名称 。Gradle核心 插件的特别之处在于它们提供了简短的名称,比如核心 JavaPluginjava。所有其他的二进制插件都必须使用完全限定的插件 id 格式(例如 com.github.foo.bar) 。

你可以使用 apply false 语法告诉 Gradle 不要将插件应用到当前项目,然后在子项目的构建脚本中使用没有版本的plugins{}块:

build.gradle

plugins {
    // 使用核心插件
    id 'java'
    // 使用社区插件
    id 'com.jfrog.bintray' version '1.8.5'
    // 使用apply false
    id 'com.example.goodbye' version '1.0.0' apply false
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

hello-a/build.gradle

plugins {
    // 子项目使用没有版本的plugin
    id 'com.example.hello'
}
  • 1
  • 2
  • 3
  • 4

插件语法

build.gradle

plugins {
    id «plugin id»                                            
    id «plugin id» version «plugin version» [apply «false»]   
}
  • 1
  • 2
  • 3
  • 4

核心JVM插件

所有核心插件请看: https://docs.gradle.org/current/userguide/plugin_reference.html


java-library

java-library 提供api依赖约束, api约束用于传递依赖

plugins {
    id 'java-library'
}
dependencies {
    api 'org.apache.httpcomponents:httpclient:4.5.7'
    implementation 'org.apache.commons:commons-lang3:3.5'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

具体: https://docs.gradle.org/current/userguide/java_library_plugin.html

application

application 插件有助于创建可执行的 JVM 应用程序。

plugins {
    id 'application'
}
//定义可执行的类
application {
    mainClass = 'org.gradle.sample.Main'
    //JVM参数
    applicationDefaultJvmArgs = ['-Dgreeting.language=en']
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可以通过gradle rungradle run --debug-jvm来启动

具体: https://docs.gradle.org/current/userguide/application_plugin.html


java-platform

java-platform插件带来了为 Java 生态系统声明平台的能力。平台可用于:

  • 共享相同的版本
  • 一组推荐的异构库版本。一个典型的例子包括 Spring Boot BOM
  • 在子项目之间共享一组依赖版本

Maven BOM 和 Java 平台之间的一个主要区别是,在 Gradle,依赖关系和约束被声明并限定在配置和扩展配置的范围内。

plugins {
    id 'java-platform'
}
dependencies {
    constraints {
        api 'commons-httpclient:commons-httpclient:3.1'
        runtime 'org.postgresql:postgresql:42.2.5'
        //本地项目约束
        api project(":lib")
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

子项目从平台获取依赖版本

dependencies {
    // 从平台项目获取推荐版本
    api platform(project(':platform'))
    // 不需要声明版本
    api 'commons-httpclient:commons-httpclient'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

获取三方约束

build.gradle

javaPlatform {
    allowDependencies()
}

dependencies {
    api platform('com.fasterxml.jackson:jackson-bom:2.9.8')
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

发布平台约束

build.gradle

publishing {
    publications {
        myPlatform(MavenPublication) {
            from components.javaPlatform
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

平台约束后面还会再次提及

详细: https://docs.gradle.org/current/userguide/java_platform_plugin.html


groovy

Groovy 插件扩展了 Java 插件以添加对 Groovy 项目的支持。

java插件类似,布局中的java名全部换为groovy

使用:

build.gradle

plugins {
    id 'groovy'
}
dependencies {
    // groovy开发
    implementation 'org.codehaus.groovy:groovy-all:2.4.15'
    // groovy 测试
    testImplementation 'org.codehaus.groovy:groovy-all:2.4.15'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

详细: https://docs.gradle.org/current/userguide/groovy_plugin.html


scala

Scala 插件扩展了 Java 插件,增加了对 Scala 项目的支持。

与groovy类似。

build.gradle

plugins {
    id 'scala'
}
dependencies {
    implementation 'org.scala-lang:scala-library:2.11.12'
    testImplementation 'org.scalatest:scalatest_2.11:3.0.0'
    testImplementation 'junit:junit:4.13'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

详细: https://docs.gradle.org/current/userguide/scala_plugin.html


创建多个项目

声明项目

项目布局

├── app
│   ...
│   └── build.gradle
├── lib
│   ...
│   └── build.gradle
└── settings.gradle
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这是推荐的项目结构,包含app和lib项目。
注意,根项目可以不用 build.gradle 文件,只有一个定义要包含的子项目的settings.gradle文件。

settings.gradle

rootProject.name = 'basic-multiproject'
include 'app'
//分隔符可以定义路径
include 'lib'
  • 1
  • 2
  • 3
  • 4

命名提示

  • 对所有项目名称使用 kebab 大小写格式: kebab 大小写格式是指所有字母都是小写,单词之间用破折号(‘-’)分隔(例如 kebab-case-format)。
  • 在设置文件中定义根项目名称: rootProject.name 有效地将一个名称分配给构建作为一个整体,该名称在诸如构建扫描之类的报告中使用。如果没有设置根项目名称,那么该名称将是容器目录名称

共享构建

https://docs.gradle.org/current/userguide/sharing_build_logic_between_subprojects.html


buildSrc

我们建议将约定插件的源代码和测试放在项目根目录中的特殊 buildSrc 目录中。

buildSrc 目录在构建时会被包含, Gradle 会自动编译和测试这段代码,并将其放到构建脚本的类路径中。对于多项目构建,只能有一个 buildSrc 目录,该目录必须位于根项目目录中。BuildSrc 应该优于脚本插件,因为它更容易维护、重构和测试代码。


buildSrc项目案例

假设我们的所有项目都是 Java 项目。在这种情况下,我们希望将一组公共规则应用于所有这些规则,例如源目录布局、编译器标志、代码样式约定、代码质量检查等等。

项目结构

├── internal-module
│   └── build.gradle
└── settings.gradles
  • 1
  • 2
  • 3

构建逻辑

├── buildSrc
│   ├── build.gradle
│   ├── settings.gradle
│   ├── src
│   │   ├── main
│   │   │   └── groovy
│   │   │       ├── myproject.java-conventions.gradle //1
│   │   │       └── myproject.library-conventions.gradle //2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
1. `myproject.java-conventions` 组织中任何 Java 项目的约定。它应用核心 java 和 checkstyle 插件以及外部 com.github.spotbug 插件,配置常见的编译器选项以及代码质量检查。
2. `myproject.library-conventions` 添加发布配置到maven存储库的约定,并检查 README 中的强制性内容。它应用了 `java-library` 和 `maven-publish` 插件,以及 `myproject.java-conventions` 插件。
  • 1
  • 2
  1. buildSrc目录下创建 build.gradle

buildSrc/build.gradle

plugins {
    id 'groovy-gradle-plugin'  //1
}
dependencies {
    // libs后面介绍
    implementation libs.spotbugs.gradle.plugin
    testImplementation platform(libs.spock.bom) //2
    testImplementation 'org.spockframework:spock-core'
}

tasks.named('test') {
    useJUnitPlatform()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
1. 为了发现预编译的脚本插件,buildSrc 项目需要在 build.gradle 文件中应用 `groovy-gradle-plugin` 插件:
2. 使用libs.spock.bom约束
  • 1
  • 2
  1. 定义 Java 项目插件、依赖规范和约束

buildSrc/src/main/groovy/myproject.java-conventions.gradle

plugins {
    id 'java'
    id 'checkstyle'

    // NOTE: external plugin version is specified in implementation dependency artifact of the project's build file
    id 'com.github.spotbugs'
}
dependencies {
    constraints {
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  1. 使用Java规范, internal-module 使用 myproject.java-conventions插件。

internal-module/build.gradle

plugins {
    // 现在这里可以使用buildSrc中自定义的插件、约束了
    id 'myproject.java-conventions'
}

dependencies {
    // internal module dependencies
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. library-a使用发布插件,可以更快发布到maven仓库中。

library-a/build.gradle

plugins {
    id 'myproject.library-conventions'
}

dependencies {
    implementation project(':internal-module')
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

subprojects {}allprojects {}

另一种不鼓励在子项目之间共享构建逻辑的方法是通过subprojects{}和所有allprojects{} DSL 构造进行跨项目配置。通过交叉配置,可以将构建逻辑注入到子项目中,而在查看子项目的构建脚本时,这一点并不明显,这使得理解特定子项目的逻辑变得更加困难。从长远来看,交叉配置通常变得越来越复杂,越来越多的条件逻辑和更高的维护负担。交叉配置还可以在项目之间引入配置-时间耦合,这可以防止像按需配置这样的优化正常工作。


项目依赖、插件

依赖仓库管理

https://docs.gradle.org/current/userguide/declaring_repositories.html

可以在~/.gradle目录下创建init.gradle为所有项目定义默认的存储仓库

声明多个存储库

repositories {
    mavenCentral()
    maven {
        url "https://repo.spring.io/release"
    }
    maven {
        url "https://repository.jboss.org/maven2"
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

项目依赖

软件项目很少单独工作。在大多数情况下,项目依赖于库形式的可重用功能,或者分解成单个组件来构成模块化系统。依赖关系管理是一种以自动方式声明、解析和使用项目所需的依赖关系的技术。

声明依赖
配置名称描述
api声明编译时和运行时可传递导出的依赖项。(需要使用 java-library 插件)
implementation声明的依赖项纯粹是内部的,不应该公开给消费者(它们在运行时仍然公开给消费者)。
compileOnly声明在编译时需要但在运行时不需要的依赖项。这通常包括在运行时找到时阴影的依赖项。
compileOnlyApi声明模块和使用者在编译时需要但在运行时不需要的依赖项。这通常包括在运行时找到时阴影的依赖项。
runtimeOnly声明只在运行时需要,而不是在编译时需要的依赖项。
testImplementation声明用于编译测试的依赖项。
testCompileOnly声明仅在测试编译时需要,但不应在到运行时使用的依赖项。
testRuntimeOnly声明仅在测试运行时而不是在测试编译时需要的依赖项

build.gradle

plugins {
    id 'java-library'
}
dependencies {
    api 'org.springframework.boot:spring-boot-starter-web'
    implementation 'log4j:log4j:1.2.12'
    testImplementation 'org.junit.jupiter:junit-jupiter'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

项目依赖

settings.gradle

rootProject.name = 'dependencies-java'
include 'api'
include 'service'
  • 1
  • 2
  • 3

service/build.gradle

dependencies {
    //导入其他项目
    implementation project(':producer')
}
  • 1
  • 2
  • 3
  • 4

这里service项目依赖api项目


依赖管理

版本目录

使用dependencyResolutionManagement组件或libs.versions.toml文件声明版本目录

  1. dependencyResolutionManagement

    dependencyResolutionManagement用于设置版本目录

    声明版本目录

    版本目录可以在 setings.gradle(kts)中声明。为了通过 libs 目录使 groovy 可用,我们需要将 (别名与组、工件、版本坐标) 关联起来:

    settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            // 默认目录
            libs {
                //声明版本
                version('groovy', '3.0.5')
                version('checkstyle', '8.37')
                //声明库
                library('groovy-core', 'org.codehaus.groovy:groovy:3.0.5')
                library('groovy-json', 'org.codehaus.groovy:groovy-json:3.0.5')
                library('groovy-nio', 'org.codehaus.groovy:groovy-nio:3.0.5')
                library('commons-lang3', 'org.apache.commons', 'commons-lang3').version {
                    strictly '[3.8, 4.0['
                    prefer '3.9'
                }
                //声明绑定
                bundle('groovy', ['groovy-core', 'groovy-json', 'groovy-nio'])
                //声明插件
                plugin('jmh', 'me.champeau.jmh').version('0.6.5')
            }
            // 多目录, 多目录必须使用 Libs 结尾的名称
            testLibs {
                def junit5 = version('junit5', '5.7.1')
                library('junit-api', 'org.junit.jupiter', 'junit-jupiter-api').version(junit5)
                library('junit-engine', 'org.junit.jupiter', 'junit-jupiter-engine').version(junit5)
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    别名必须包含一系列由破折号(- ,推荐)、下划线(_)或点(.)分隔的标识符.标识符本身必须由 ascii 字符组成,最好是小写字母,最后是数字。

    我们将生成以下类型安全的访问器:

    • libs.guava
    • libs.groovy.core
    • libs.groovy.xml
    • libs.groovy.json
    • libs.androidx.awesome.lib

    如果您希望避免生成子组访问器,我们建议依靠大小写来区分。例如,别名 groovyCoregroovyJsongroovyXml 将分别映射到 libs.groovyCorelibs.groovyJsonlibs.groovyXml 访问器。

    在声明别名时,值得注意的是"-"、'_‘和’.'中的任何字符可以用作分隔符,但生成的目录将全部规范化为点(.): 例如 foo-bar 作为别名被自动转换为 foo.bar

    使用版本目录

    build.gradle

    // 使用目录插件
    plugins {
        id 'java-library'
        id 'checkstyle'
        // Use the plugin `jmh` as declared in the `libs` version catalog
        alias(libs.plugins.jmh)
    }
    alias(libs.plugins.jmh)
    // == 直接版本目录依赖 
    dependencies {
        implementation libs.groovy.core
        implementation libs.groovy.json
        implementation libs.groovy.nio
    }
    // == 等效于, 使用绑定 
    dependencies {
        implementation libs.bundles.groovy
    }
    // == 等效于, 通常定义依赖 
    dependencies {
        //使用目录依赖
        implementation 'org.codehaus.groovy:groovy:3.0.5'
        implementation 'org.codehaus.groovy:groovy-json:3.0.5'
        implementation 'org.codehaus.groovy:groovy-nio:3.0.5'
        //使用目录绑定,等效于使用上面的目录依赖
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  2. 使用libs.versions.toml文件

    Gradle 还提供了一个声明目录的常规文件。如果在根构建的 gradle的子目录中找到 libs.versions.toml 文件,那么将自动声明一个包含该文件内容的目录。
    默认情况下,libs.versions.toml 文件将作为 libs 目录的输入。可以更改默认目录的名称,例如,如果您已经有一个具有相同名称的扩展名:

    settings.gradle

    dependencyResolutionManagement {
        defaultLibrariesExtensionName.set('projectLibs')
    }
    
    • 1
    • 2
    • 3

    TOML 文件由4个主要部分组成:

    • [version]: 用于声明可由依赖项引用的版本。
    • [library]: 用于将别名声明为坐标。
    • [bundles]: 用于声明依赖性 bundle。
    • [plugins]: 部分用于声明插件。

    这些都在上面讲过了,就不多说了。

    版本目录声明

    gradle/libs.versions.toml

    [versions] #1
    groovy = "3.0.5"
    checkstyle = "8.37"
    
    [libraries]
    groovy-core = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" } #2
    groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" }
    groovy-nio = { module = "org.codehaus.groovy:groovy-nio", version.ref = "groovy" }
    commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version = { strictly = "[3.8, 4.0[", prefer="3.9" } }
    
    [bundles]
    groovy = ["groovy-core", "groovy-json", "groovy-nio"]
    
    [plugins]
    jmh = { id = "me.champeau.jmh", version = "0.6.5" }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    命名规则同 dependencyResolutionManagement 命名规则一样

    版本可以声明为单个字符串(在这种情况下,它们被解释为必需的版本) ,也可以声明为富版本:

    • require: 必需的版本
    • strictly: 严格的版本
    • prefer: 首选版本
    • reject: 被拒绝版本的列表
    • rejectAll: 拒绝所有版本
    [versions]
    my-lib = { strictly = "[1.0, 2.0[", prefer = "1.2" }
    
    • 1
    • 2

    与 buildSrc 共享依赖项目录

    buildSrc/settings.gradle

    dependencyResolutionManagement {
        versionCatalogs {
            libs {
                from(files("../gradle/libs.versions.toml"))
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    发布版本目录插件
    可以通过使用 maven-publish 插件或 ivy-publish 插件,并将发布配置为使用 versionCatalog 组件来发布这样的目录

    当发布这样一个项目时,将自动生成(并上传)一个 libs.versions.toml 文件,然后可以从其他 Gradle 版本中使用该文件。

    build.gradle

    plugins {
        id 'version-catalog'
        id 'maven-publish'
    }
    publishing {
        publications {
            maven(MavenPublication) {
                from components.versionCatalog
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    导入已发布的目录

    dependencyResolutionManagement {
        versionCatalogs {
            libs {
                from("com.mycompany:catalog:1.0")
            }
            //覆盖目录
            amendedLibs {
                from("com.mycompany:catalog:1.0")
                version("groovy", "3.0.6")
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

使用平台 (platform) 控制依赖版本

平台是一种特殊的基于组件的软件工程,可用于控制传递依赖版本。在大多数情况下,它完全由依赖关系约束组成,这些约束要么建议依赖关系版本,要么强制执行某些版本。因此,当您需要在项目之间共享依赖版本时,这是一个完美的工具。

获取平台中声明的版本

build.gradle

dependencies {
    // 从平台项目中获取推荐版本
    api platform(project(':platform'))
    //不需要版本
    api 'commons-httpclient:commons-httpclient'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

导入Maven BOMs

build.gradle

dependencies {
    // 导入BOM
    implementation platform('org.springframework.boot:spring-boot-dependencies:1.5.8.RELEASE')
    implementation 'com.google.code.gson:gson'
    implementation 'dom4j:dom4j'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Gradle 处理 BOM<DepencyManagement> 块中的所有条目,类似于 Gradle 的依赖约束。


应该使用平台还是目录

因为平台和目录都讨论依赖版本,并且都可以用于在项目中共享依赖版本,所以在使用什么以及是否使用其中一个优于另一个方面可能会有混淆。

简而言之,你应该:

  • 使用目录只为项目定义依赖项及其版本,并生成类型安全的访问器
  • 使用平台将版本应用到依赖关系图并影响依赖关系解析

学习以官方文档为主,如有问题请指教!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/288306
推荐阅读
相关标签
  

闽ICP备14008679号