跳至主要內容

1、Gradle是什么

gavin-james大约 30 分钟

[TOC]

1、Gradle是什么

1.1 简介

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具;官网open in new window

  • Gradle是一个基于JVM的构建工具
  • 是一款通用灵活的构建工具
  • 支持maven, Ivy仓库
  • 支持传递性依赖管理,而不需要远程仓库或者是pom.xml和ivy.xml配置文件
  • 基于Groovy,build脚本使用Groovy编写
  • 它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置
  • 目前也增加了基于Kotlin语言的kotlin-based DSL,抛弃了基于XML的各种繁琐配置
  • 面向Java应用为主。当前其支持的语言C++、Java、Groovy、Kotlin、Scala和Swift,计划未来将支持更多的语言
  • gradle对多工程的构建支持很出色,工程依赖是gradle的第一功能
  • gradle支持局部构建
  • 支持多方式依赖管理:包括从maven远程仓库、nexus私服、ivy仓库以及本地文件系统的jars或者dirs
  • gradle是第一个构建集成工具,与ant、maven、ivy有良好的相容相关性
  • 轻松迁移:gradle适用于任何结构的工程,你可以在同一个开发平台平行构建原工程和gradle工程。通常要求写相关测试,以保证开发的插件的相似性,这种迁移可以减少破坏性,尽可能的可靠。这也是重构的最佳实践
  • gradle的整体设计是以作为一种语言为导向的,而非成为一个严格死板的框架
  • 免费开源

1.2 Gradle发展史

ant-----ivy

  • 2000年

  • 使用XML作为一种格式来写构建脚本

  • XML是分层的,不利于程序的编程,而且当XML文件变大以后变得难以管理

  • tomcat仍然使用的ant进行项目搭建

maven----resipotory

  • 2004年
  • 依赖xml

gradle

  • 2012年

  • 是一个基于Apache Ant和Apache Maven概念的项目构建工具

  • 它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置

  • 面向Java应用为主,当前其支持的语言限于Jdava、Groovy和Scala,计划未来将支持更多的语言

生存周期:

  • 依赖约定和能够通过网络下载依赖关系。
  • Maven的主要好处是它的生命周期。虽然接连的多个项目生命周期相同,这是以灵活性为代价的

1.3 为什么使用Groovy

完整的Gradle API是使用Groovy语言设计的

  • 这是基于XML内部DSL的优点

  • Gradle是其核心的通用构建工具;它的主要焦点是Java项目

  • 在这些项目中,团队成员要熟悉Java,这是为了更好的构建透明,给所有团队成员的项目

  • 类似于Python , Groovy或Ruby语言是最好的构建框架

  • 为什么Groovy被选中?这是因为它为使用ava的人提供了迄今为止最大的透明度。Groovy的基本语法与ava是一样的

Java, Groovy, Scala 语言可以混写,最终都会被编成.class字节码文件

  • Groovy可以调用JVM的方法

2、Gradle安装配置

下载地址:https://services.gradle.org/distributions/open in new window

配置环境变量:

  1. GRADLE_HOME+安装的目录
  2. path:加上%GRADLE_HOME%\bin
  3. 本地仓库构建:GRADLE_USER_HOME+MAVEN的仓库
  4. 镜像配置:在build.gradle中加上
allprojects {
    repositories {
        //使gradle先加载本地仓库再去加载中央仓库
        mavenLocal()
        maven {
            url 'https://maven.aliyun.com/repository/public/'
        }
        maven {
            url 'https://maven.aliyun.com/repository/google/'
        }
        maven {
            url 'https://maven.aliyun.com/repository/gradle-plugin/'
        }
        maven {
            url 'https://maven.aliyun.com/repository/spring/'
        }
        maven {
            url 'https://maven.aliyun.com/repository/spring-plugin/'
        }
        maven {
            url 'https://maven.aliyun.com/repository/grails-core/'
        }
        maven {
            url 'https://maven.aliyun.com/repository/apache-snapshots/'
        }
        maven {
            url 'https://repo.spring.io/'
        }
        maven {
            url 'https://repo.spring.io/plugins-release'
        }
        mavenCentral()
        jcenter()
    }
    //指定jdk版本
    sourceCompatibility = 8
    //指定编码格式
    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }
}
//配置子项目的资源库
subprojects {
}

3、项目构建

3.1Gradle构建脚本

每个Gradle生成表示一个或多个项目

  • 一个项目表示一个JAR库或Web应用程序,也可能表示由其他项目产生的JAR文件组装的ZIP

  • 简单地说,一个项目是由不同的任务组成

  • 一个任务是指构建执行的一块工作

  • 任务可能是编译一些类,创建一个]AR,产生的]avadoc或发布一些归档文件库

Gradle提供了一个域特定语言(DSL),用于描述构建。它使用Groovy语言,使其更容易来形容和构建。

  • Gradle中的每一个构建脚本使用UTF-8进行编码保存,并命名为build.gradle

3.1.1 创建build.gradle文件

  • gradle最小运算单元:task

    task firstgvy{
        doLast {
            println('this is the first gradle')
        }
    }
    task upper{
        doLast {
            String expStr = 'yyj'
            println "original:"+expStr
            println "upper case:"+expStr.toUpperCase()
        }
    }
    task count{
        doLast {
            4.times {
                print "$it "
            }
            println("")
        }
    }
    
  • 终端执行

    # 在Execution阶段执行groovy任务,3阶段一起执行
    # -q 静默状态执行,Log只显示错误日志
    F:\codes_202103\gradlestudy>gradle -q firstgvy
    this is the first gradle
    F:\codes_202103\gradlestudy>gradle -q upper
    original:yyj
    upper case:YYJ
    F:\codes_202103\gradlestudy>gradle -q count
    0 1 2 3
    

3.1.2 build的三个阶段

gradle构建的生命周期主要分为三个阶段,Initialization , Configuration,Execution

  • lnitialization : Gradle支持单个或多个工程的构建

    • Gradle决定哪些工程将参与到当前构建过程,并为每一个这样的工程创建一个Project实例
    • 一般情况下,参与构建的工程信息将在settings.gradle中定义
      • settings.gradle 存放工程信息
  • Configuration:

    • 在这一阶段,配置project的实例
    • 所有工程的构建脚本都将被执行
      • Task , configuration和许多其他的对象将被创建和配置
  • Execution :

    • 在之前的configuration阶段,task的一个子集被创建并配置
      • 这些子集来自于作为参数传入gradle命令的task名字
      • 在execution阶段,这一子集将被依次执行

问题: doLast语句处于哪个阶段?

  • 到执行阶段,3阶段都执行

2类task

  • 加doLst

    • 在Execution阶段执行
  • 不加doLast

    • 在Configuration阶段执行
task firstgvy{
//    doLast {
        println('this is the first gradle')
//    }
}

println "this is the outside gradle"
task secondgvy{
    println "this is the inside gradle"
    doLast {
        println('this is the second gradle')
    }
}
# 只走到配置阶段执行
D:\Coding\OnlineStudy\gradlestudy>gradle

> Configure project :
this is the first gradle
this is the outside gradle
this is the inside gradle

> Task :help

Welcome to Gradle 6.8.3.

To run a build, run gradle <task> ...

To see a list of available tasks, run gradle tasks

To see a list of command-line options, run gradle --help

To see more detail about a task, run gradle help --task <task>

For troubleshooting, visit https://help.gradle.org

BUILD SUCCESSFUL in 992ms
1 actionable task: 1 executed

3.1.3 groovy的JDK方法

  • Groovy增加了很多有用的方法到标准的Java类
    • 如从Java API可迭代实现它遍历Iterable接口的元素的each方法
task groovyJDKMethod{
    String myName = "yyj"
    myName.each(){
        println "${it}"
    }
}

3.2 Gradle任务

  • 不加{}也能执行
  • 加{}形成闭包

3.2.1 任务依赖

方式1~参数

task groovyJDKMethod{
    String myName = "yyj"
    //JDK String.each方法
    myName.each(){
        println "${it}"
    }
}

task wdf(dependsOn:groovyJDKMethod){
    doLast{
        println "wonderful!"
    }
}
-------------输出---------------------
D:\Coding\OnlineStudy\gradlestudy>gradle -q wdf
y
y
j
wonderful!

方式2~task1.dependsOn task2

  • 要将一个任务依赖于另一个任务,这意味着当一个任务完成时,另一个任务将开始

  • 每个任务都使用任务名称进行区分

  • 任务名称集合由其任务集合引用

  • 要引用另一个项目中的任务,应该使用项目路径作为相应任务名称的前缀

task upper{
    doLast {
        String expStr = 'yyj'
        println "original:"+expStr
        println "upper case:"+expStr.toUpperCase()
    }
}
task count{
    doLast {
        4.times {
            print "$it "
        }
        println("")
    }
}

count.dependsOn upper
-------------输出---------------------
D:\Coding\OnlineStudy\gradlestudy>gradle -q count
upper case:YYJ
0 1 2 3

方式3~使用闭包

  • 任务通过闭包释放,如果在构建脚本中使用闭包,依赖于多个任务对象
task upper{
    doLast {
        String expStr = 'yyj'
        println "original:"+expStr
        println "upper case:"+expStr.toUpperCase()
    }
}

upper.dependsOn{
    tasks.findAll{
        task->task.name.startsWith('lib')
    }
}

3.2.2 定位任务

  • 如果要查找在构建文件中定义的任务,则必须使用相应的标准项目属性

    • 这意味着每个任务都可以作为项目的属性,使用任务名称作为属性名称
  • 还可以通过任务集合使用所有属性

task yyj
println yyj.name
println project.yyj.name

println tasks.yyj.name
println tasks['yyj'].name
-------------输出---------------------
D:\Coding\OnlineStudy\gradlestudy>gradle -q yyj
yyj
yyj
yyj
yyj

3.2.3 向任务添加描述

  • 使用description关键字:可以向任务添加描述,增加可读性
task copyTask(type:Copy){
    description 'Copy the resource directory to the target directory'
    from 'resouces'
    into 'target'
    include('**/*.txt', '**/*.xml', '**/*.properties')
    println("description applied")
}
-------------输出---------------------
D:\Coding\OnlineStudy\gradlestudy>gradle -q copyTask
description applied

3.2.4 跳过任务

  • 如果用于跳过任务的逻辑不能用谓词表示,则可以使用stopExecutionException
    • 如果操作抛出此异常,则会跳过此操作的进一步执行以及此任务的任何后续操作的执行, 构建继续执行下一个任务
task compile{
    doLast{
        println "compile."
    }
}

// compile的前置任务:如果这个执行异常,compile不执行
compile.doFirst{
    if(true){throw new Exception()}
}

task myTask(dependsOn: 'compile'){
    doLast{
        println "myTask."
    }
}

4、Gradle依赖管理

  • Gradle构建脚本定义了构建项目的过程

    • 每个项目包含一些依赖项和一些发表项
      • 依赖性意味着支持构建项目的东西
        • 例如来自其他项目的所需JAR文件以及类路径中的外部JAR
      • 发布项目的结果
        • 如测试类文件和构建文件,如war文件。
  • Gradle负责构建和发布结果

    • 发布基于定义的任务
    • 可能希望将文件复制到本地目录,或将其上传到远程Maven或lvy存储库,或者可以在同一个多项目构建中使用另一个项目的文件

4.1 声明依赖关系

Gradle遵循一些特殊语法来定义依赖关系

// 引用java插件:引入大量task,如clean,jar,build,init,wrapper,javadoc,check,test
apply plugin: 'java'

// maven仓库
repositories {
    mavenCentral()
}

// maven的scope对应gradle的group
// 依赖关系
dependencies{
    compile group: 'org.hibernate', name:'hibernate-core', version:'5.4.2.Final'
    testCompile group: 'junit', name:'junit', version:'5.+'
}

4.2 依赖关系配置

在对应的scope范围内生效:

  • 依赖关系配置只是定义了一组依赖关系

    • 使用此功能声明从Web下载外部依赖关系
  • 定义了以下不同的标准配置

    • 编译【被弃用】
      • 编译项目的生产源所需的依赖关系
    • 运行时
      • 运行时生产类所需的依赖关系
      • 默认情况下,还包括编译时依赖项
    • 测试编译
      • 编译项目测试源所需的依赖项
      • 默认情况下,它包括编译的产生的类和编译时的依赖
    • 测试运行时–运行测试所需的依赖关系
      • 默认情况下,它包括运行时和测试编译依赖项

4.2.1 Java用于声明依赖的配置

配置名称角色Consumable?Resolvable?Description
api声明 API 依赖项nono这是您声明依赖项的地方,这些依赖项可传递地导出到使用者,用于编译时和运行时。
implementation声明实现依赖nono这是您声明纯粹内部的依赖项的地方,并不打算向消费者公开(它们在运行时仍然向消费者公开)。
compileOnly声明仅编译依赖项nono这是您声明在编译时需要但在运行时不需要的依赖项的地方。这通常包括在运行时发现的依赖项。
compileOnlyApi声明仅编译 API 依赖项nono您可以在此处声明模块和使用者在编译时需要的依赖项,但在运行时不需要。这通常包括在运行时发现的依赖项
runtimeOnly声明运行时依赖项nono这是您声明仅在运行时需要的依赖项,而不是在编译时需要的依赖项。
testImplementation测试依赖nono这是您声明用于编译测试的依赖项的地方。
testCompileOnly声明测试只编译依赖项nono这是您声明仅在测试编译时需要但不应泄漏到运行时的依赖项的地方。这通常包括在运行时发现的依赖项。
testRuntimeOnly声明测试运行时依赖项nono这是您声明仅在测试运行时需要的依赖项,而不是在测试编译时需要的依赖项。

下图描述了在使用Java库插件时配置。

配置
配置
  • 绿色的配置是用户应该用于声明依赖的配置

  • 粉红色中的配置是组件编译或对库运行时使用的配置

  • 蓝色配置是组件内部的,因为它可以使用

下图描述了测试配置设置:

测试配置
测试配置

4.3 外部依赖

外部依赖是一种依赖

  • 这是对当前构建之外构建的一些文件的依赖,并且存储在某种类型的存储库中
    • 例如:Maven central , corporate Maven或lvy repository或本地文件系统中的目录
dependencies{
    compile group: 'org.hibernate', name:'hibernate-core', version:'5.4.2.Final'
}

4.4 存储库

  • 在添加外部依赖关系时,Gradle在存储库中查找它们

    • 存储库只是文件的集合,按分组,名称和版本来组织构造
    • 默认情况下,Gradle不定义任何存储库
    • 必须至少明确地定义一个存储库
  • 一个Java工程通常会依赖于外部的jar包,Gradle可以使用Maven的仓库来获取或者发布相应的jar包

setting.gradle:

pluginManagement{
    repositories{
        //阿里云镜像
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
        maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
        mavenCentral()
        gradlePluginPortal()
        maven {
            url 'https://repo.spring.io/plugins-release'
        }
//        if(version.endsWith('BUILD-SNAPSHOT')){
//            maven{ url "https://repo.spring.io/snapshot"}
//        }
    }
    resolutionStrategy{
        eachPlugin{
//            if(request.id.id == "org.jetbrains.kotlin.jvm"){
//                useVersion "${kotlinVersion}"
//            }
//            if(request.id.id == "org.jetbrains.kotlin.plugin.spring"){
//                useVersion "${kotlinVersion}"
//            }
        }
    }
}
plugins{
//    id 'com.gradle.enterprise' version "6.8.3"
}
rootProject.name = 'gradlestudy'

4.5 发布文件

  • 依赖关系配置也用于发布文件,这些已发布的文件称为工件

    • 通常,我们使用插件来定义工件
    • 但是需要告诉Gradle在哪里发布文件
      • 可以通过将存储库附加到上传存档任务来实现此目的
  • 执行时,Gradle将根据项目需求生成并上传pom.xml,在build.gradle文件中使用此代码

apply plugin: 'maven'

uploadArchives{
    reposities{
        mavenDeployer{
            repository(url:"file://localhost/tmp/myRepo")
        }
    }
}


// 这是自己的阿里云仓库
group '[GROUP_ID]'
version '[VERSION]'
def artifactId = '[ARTIFACT_ID]'

// 文件具体推送到哪个库,根据您项目目录的build.gradle文件中version字段中是否配置了-SNAPSHOT。
apply plugin: 'maven-publish'

// 上传source
task sourcesJar(type: Jar) {
    from sourceSets.main.allJava
    archiveClassifier.set("sources")
}

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
            versionMapping {
                usage('java-api') {
                    fromResolutionOf('runtimeClasspath')
                }
                usage('java-runtime') {
                    fromResolutionResult()
                }
            }
            // 主要是这一行
            artifact sourcesJar
        }
    }

    // 私有仓库仓库地址
    repositories {
        maven {
            // change URLs to point to your repos, e.g. http://my.org/repo
            def releasesRepoUrl = 'https://packages.aliyun.com/maven/repository/2173289-release-vctkTy/'
            def snapshotsRepoUrl = 'https://packages.aliyun.com/maven/repository/2173289-snapshot-g5yEdX/'
            url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
            credentials {
                username = '61ce7cfea96ac5d9b038f98c'
                password = 'Ywnuvi=(4e9d'
            }
        }
    }
}

注意:

  • 这里由于本地没有该仓库,因此该步骤需要被注释,否则会报错

5、Gradle插件

  • 插件只是一组任务
    • 几乎所有的任务,如编译任务,设置域对象,设置源文件等都由插件处理

5.1 插件类型

Gradle中有两种类型的插件∶ 脚本插件和二进制插件

  • 脚本插件是一个额外的构建脚本,它提供了一种声明性方法来操作构建,通常在构建中使用

  • 二进制插件是实现插件接口并采用编程方法来操作构建的类

    • 二进制插件可以驻留在插件JAR中的一个构建脚本和项目层次结构或外部
  • Project.apply() API方法用于应用特定的插件, 可以多次使用相同的插件

5.1.1脚本插件

脚本插件可以从本地文件系统进行应用,文件系统位置相对于项目目录,而远程脚本位置指定HTTP URL

other.gradle

ext{
    verson='1.0'
    url='http://yyj.cn'
}

build.gradle 使用other.gradle插件

apply from: 'other.gradle'

task testTask{
    doLast{
        println "verson:$verson, url:$url"
    }
}
D:\Coding\OnlineStudy\gradlestudy>gradle -q testTask
verson:1.0, url:http://yyj.cn

5.1.2 二进制插件【对象插件】

  • 每个插件由插件标识,一些核心插件是使用短名称来应用它,一些社区插件是使用插件ID的完全限定名称,有时它允许指定一个插件类
    • 二进制插件就是实现了org.gradle.api.Plugin接口的插件,它们可以有Plugin id。
    • 通常对象插件分2类:
      • 内部插件
img
img
img
img
img
img

内部插件1~对应插件名

apply plugin:JavaPlugin

内部插件2~使用短名称应用核心插件:

  • 也称为插件DSL
plugins{
    id 'java'
}

//或者这种也可以
apply plugin: 'java'
img
img

第三方插件

plugins {
  id "com.jfrog.bintray" version "1.8.5"
}
  • 或者按如下方式使用
    • 第三方的对象插件通常是jar文件,要想让构建脚本知道第三方插件的存在,需要使用buildScript来设置
    • 如果没有被托管到gradle, 那么就只能用该方式使用该插件
buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5"
  }
}

apply plugin: "com.jfrog.bintray"

5.2 编写自定义插件

5.2.1 自定义插件

在创建自定义插件时,需要编写一个插件的实现

  • Gradle实例化插件并使用Plugin. apply()方法调用插件实例

build.gradle

apply plugin:HelloPlugin

class HelloPlugin implements Plugin<Project>{
    void apply(Project project){
        project.task('hello'){
            doLast{
                println "Hello from the HelloPlugin."
            }
        }
    }
}
D:\Coding\OnlineStudy\gradlestudy>gradle -q hello
Hello from the HelloPlugin

5.2.2 自定义插件扩展

  • 大多数插件需要从构建脚本中的配置获得支持,Gradle项目有一个关联"ExtensionContainer"对象,它有助于跟踪传递给插件的所有设置和属性
// 自定义插件扩展
class HelloPlugin implements Plugin<Project>{
    void apply(Project project){
        //增加一个greeting任务,扩展对象
        project.extensions.create("greeting", HelloPluginExtension)

        project.task('hello'){
            doLast{
                println "Hello from the HelloPlugin."
                println project.greeting.message
            }
        }
    }
}

class HelloPluginExtension{
    String message
}

apply plugin:HelloPlugin

greeting.message="yyj study gradle"

// 或使用该方法赋值
/*
greeting{
    message="yyj study gradle"
}*/
D:\Coding\OnlineStudy\gradlestudy>gradle -q hello
Hello from the HelloPlugin.
yyj study gradle

5.3 标准Gradle插件

5.3.1 语言插件

这些插件的添加,让JVM在编译和执行时对各种语言支持

img
img
img
img

只对某些源起作用的依赖

img
img

增加源sourset

imgimg

img
img

5.3.2 孵化语言插件

img
img

5.4 Gradle Java插件

Java插件:

  • 依赖管理

  • 增加的属性

  • 增加的任务

  • 用法

  • 源集

  • 项目目录结构

Java插件是构建JVM项目的基础,它为项目增加了很多能力

  • 例如编译,测试,打包,发布等等
  • 很多插件都是基于Java插件实现的
    • 例如Android插件

5.4.1 源集

Java插件引入了源集的概念,它在逻辑上表示一组用于编译执行的源文件,这些源文件可能包括源代码文件和资源文件

  • 一个源集有一个相关联的编译类路径和运行时类路径

  • Java插件就是通过源集的概念来管理源代码目录的

    • 源集的一个用途是,把源文件进行逻辑上的分组,以描述它们的目的
    • 例如,你可能会使用一个源集来定义一个集成测试套件,或者你可能会使用单独的源集来定义你的项目的API和实现类
  • Java插件提供了两个标准源集∶

    • main包含了项目的源代码,被用于编译和生成JAR文件
    • test包含单元测试源代码,它们将被编译并使用JUnitTestNG来执行

定义源集

imgimg

sourceSets {
    other{
        output.resourcesDir=file("out/bin")
        java.outputDir=file("out/bin")

        java{
            srcDirs=['src/other/java']
        }
        resources {
            srcDirs=['src/other/java/resources']
        }
    }
}

注意:

  • 源集的位置也很重要,不要在dependencies下面,否则对源集的依赖就将不起作用
img
img

访问源集

  • sourceSets是Java插件为Project 增加的一个属性,可以直接使用
task outSourceSet{
    doLast{
        //遍历
        sourceSets.all{
            println "$name ->"
        }
        println("-------split------")
        // 单个的
        println("${sourceSets.main.name} -->")
        println("${sourceSets['other'].name} -->")

        //一些属性
        println("java.srcDirs -->${sourceSets.other.java.srcDirs}")
        println("resource.srcDirs -->${sourceSets.other.resources.srcDirs}")
    }
}
D:\Coding\OnlineStudy\gradlestudy>gradle -q outSourceSet
main ->
other ->
test ->
-------split------
main -->
other -->
java.srcDirs -->[D:\Coding\OnlineStudy\gradlestudy\src\other\java]
resource.srcDirs -->[D:\Coding\OnlineStudy\gradlestudy\src\other\java\resources]

为源集添加依赖

  • 默认给main目录下增加依赖
    • 前面加上源集,就可以给对应的源集添加依赖,请注意有先后关系
dependencies{
    compile group: 'org.hibernate', name:'hibernate-core', version:'5.4.2.Final'
    testCompile group: 'junit', name:'junit', version:'4.13'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
    otherImplementation 'com.google.code.gson:gson:2.8.7'
}

将源集打成一个Jar包

  • 创建一个otherJar任务,将源集的输出作为任务的文件来源
  • 执行这个任务即可生成JAR包
task otherJar(type: Jar){
    archivesBaseName=sourceSets.other.name
    archiveVersion='0.1.0'
    destinationDirectory=file("${project.projectDir}/jar")
    from sourceSets.other.output
}
img
img

为源集生成doc

  • 创建一个任务将源集的所有Java文件作为源文件
tasks.withType(Javadoc){
    options.encoding='UTF-8'
}
tasks.withType(JavaCompile){
    options.encoding='UTF-8'
}
task otherDoc(type: Javadoc){
    options.addStringOption('Xdoclint:none', '-quiet')
    destinationDir = file("${project.projectDir}/doc")
    source sourceSets.other.allJava
    title sourceSets.other.name
}

注意:

  • type: 后面要有空格

项目结构

Java插件的默认目录结构如下所示

  • 无论这些文件夹中有没有内容, Java插件都会编译里面的内容,并处理没有的内容
  • 这个目录结构也是Java世界标准的项目目录
img
img

6、Gradle运行构建

Gradle提供了一个命令行来执行构建脚本

  • 它可以一次执行多个任务,在这里将介绍如何使用不同的选项来执行多个任务

6.1 执行多个任务

Gradle可以从单个构建文件执行多个任务

  • 使用grad le命令处理构建文件。此命令将按列出的顺序编译每个任务,并使用不同的选项执行每个任务以及依赖关系
  • **重复依赖的任务只执行一次**,如果命令执行成功,将获得以下输出
    • 只看直接相关

示例·假设有四个任务·task1, task2,task3和task4

img
img

imgimg

6.2 排除任务

  • 要执行中排除某个任务时,可以在gradle命令中使用-x选项,并指出要排除的任务的名称

imgimg

6.3 选择执行哪些构建

  • 当运行gradle命令时,它在当前目录中查找构建文件
  • 也可以使用-b选项选择指定的构建文件的路径

other.gradle

task hello{
    doLast {
        println "Use File:$buildFile.name in '$buildFile.parentFile.name'."
    }
}
D:\Coding\OnlineStudy\gradlestudy>gradle -q -b other.gradle hello
Use File:other.gradle in 'gradlestudy'.

6.4 获取构建信息

  • Gradle提供了几个内置任务来检索有关任务和项目的详细信息,这对理解构建的结构和依赖性以及调试一些问题很有用
    • 可使用项目报告插件向项目中添加任务,来生成这些报告

6.4.1 列出项目

  • 可以使用gradle -q projects命令来列出所选项目及其子项目的项目层次结构

other.gradle

// 对该项目的描述
description 'this is other gradle'
ext{
    verson='1.0'
    url='http://yyj.cn'
}

task hellos{
    doLast {
        println "Use File:$buildFile.name in '$buildFile.parentFile.name'."
    }
}
D:\Coding\OnlineStudy\gradlestudy>gradle -q -b other.gradle projects

------------------------------------------------------------
Root project 'gradlestudy' - this is other gradle
------------------------------------------------------------

Root project 'gradlestudy' - this is other gradle
No sub-projects

To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :tasks
D:\Coding\OnlineStudy\gradlestudy>

6.4.2 列出任务

  • 列出属于多个项目的所有任务
D:\Coding\OnlineStudy\gradlestudy>gradle -q -b other.gradle  tasks --all

------------------------------------------------------------
Tasks runnable from root project 'gradlestudy' - this is other gradle
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'gradlestudy'.
dependencies - Displays all dependencies declared in root project 'gradlestudy'.
dependencyInsight - Displays the insight into a specific dependency in root project 'gradlestudy'.
help - Displays a help message.
javaToolchains - Displays the detected java toolchains. [incubating]
outgoingVariants - Displays the outgoing variants of root project 'gradlestudy'.
projects - Displays the sub-projects of root project 'gradlestudy'.
properties - Displays the properties of root project 'gradlestudy'.
tasks - Displays the tasks runnable from root project 'gradlestudy'.

Other tasks
-----------
components - Displays the components produced by root project 'gradlestudy'. [deprecated]
dependentComponents - Displays the dependent components of components in root project 'gradlestudy'. [deprecated]
hellos
model - Displays the configuration model of root project 'gradlestudy'. [deprecated]
prepareKotlinBuildScriptModel

6.4.3 其他

img
img

7、Gradle构建Java项目

7.1 Java默认的项目布局

阿里云的构建地址: http://start.aliyun.comopen in new window

img
img
img
img
  • 如果遵循上面设置,以下构建文件足以编译,测试并捆绑Java项目
D:\Coding\OnlineStudy\gradlestudy>gradle build

> Configure project :
this is the first gradle
this is the outside gradle
this is the inside gradle
y
y
j
yyj
yyj
yyj
yyj
description applied

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.8.3/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 8s
2 actionable tasks: 2 executed

7.2 初始化任务执行

  • Gradle还不支持多个项目模板

    • 但它提供了一个init来初始化任务,来创建一个新的Gradle项目的结构
    • 如果没有指定其他参数,任务将创建一个Gradle项目,其中包含gradle包装器文件bui1d.gradlesettings.gradle文件
  • 当使用java-library作为值并添加--type参数时,将创建一个java项目结构,build.gradle文件包含带有Junit的某个Java模板

    • 在仓库(repositories )这部分中,它定义了要从哪里找到依赖
    • Jcenter是为了解决依赖,依赖关系( dependencies)部分用于提供有关外部依赖关系的信息
img
img

7.3 指定Java版本

通常,Java项目要有一个版本和一个目标JRE,在其上编译它

  • versionsourceCompatibility属性可以在build.gradle文件中设置
  • 如果这是一个可执行的Java应用程序,MANIFEST.MF 文件必须要指定具有main方法的类
apply plugin: 'java'
version="0.1.1"
sourceCompatibility=1.8
targetCompatibility=1.8

jar{
    manifest{
        attributes "Manifest-Version":1.0,
        'Main-Class':'App'
    }
}
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

//针对多模块
allprojects {
    group 'com.yyj'
    version '0.0.1-SNAPSHOT'
    repositories {
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
        maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
        mavenCentral()
        jcenter()
    }
}

repositories {
    mavenCentral()
    jcenter()
    mavenLocal()
}

//该区域是配置构建工具gradle本身所需要的依赖和仓库的代码区域,不能把工程所需要的依赖放置在这里
buildscript{
    ext{
        springBootVersion = '2.3.2.RELEASE'
    }

    //gradle自身依赖的仓库,除了jcenter , maven ,ivy之外,还支持google等
    repositories {
        maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
        maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
        maven{ url 'https://repo.spring.io/plugins-release'}
        mavenCentral()
        jcenter()
    }

    // 该区域配置了gradle编译springboot工程所需要的依赖插件
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

sourceCompatibility=1.8
targetCompatibility=1.8

jar{
    manifest{
        attributes "Manifest-Version":1.0,
                'Main-Class':'com.yyj.SpringBootApp1'
    }
}

dependencies{
    compile group: 'org.hibernate', name:'hibernate-core', version:'5.4.2.Final'
    testCompile group: 'junit', name:'junit', version:'4.13'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
    otherImplementation 'com.google.code.gson:gson:2.8.7'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.5.1'
}

tasks.withType(JavaCompile){
    options.encoding='UTF-8'
}
img
img
img
img

7.4 clean & build

  • clean 清除构建结果
  • build 重新构建项目,可以在对应目录生成Jar包
img
img

imgimg

8、Gradle测试

  • 测试任务会自动检测和执行测试源集合中的所有单元测试

  • 它还会在测试执行完成后生成报告

  • JUnit和TestNG都是支持的API

8.1 测试检测

  • 测试任务通过检查编译的测试类来检测哪些类是测试类

    • 默认情况下,它扫描所有.class文件,不过也可以设置自定义包含/排除,只有那些类才会被扫描
  • 根据所使用的测试框架([Junit / TestNG ),测试类检测使用不同的标准

  • 如果不想使用测试类检测,可以通过将scanForTestclasses设置为false来禁用它

build.gradle

test {
    // 默认使用Junit
    useJUnitPlatform()
    // 使用testNG
    useTestNG()
}

测试用例:

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

/**
 * @ClassName: AppTest
 * @Description:
 * @author: sunjr on 2021-06-13 19:17
 * @Version: 1.0
 **/

public class AppTest {
    @Test
    public void test(){
        String test = "test";
        Assertions.assertEquals("test", test);
    }
}
img
img

8.2 包括和排除指定测试

  • Test类有一个include和exclude方法。这些方法可以用于指定哪些测试应该运行

8.2.1 使用Junit框架

  • 注意:Junit和testNG不要同时使用,可能会造成build/test/test/packages出不来
test {
    // 默认使用Junit
    useJUnitPlatform()
}

禁用测试:

test{
    //跳过测试用例
    enabled=false
}

只运行包含的测试

test{
    include 'com/yyj/*'
}

跳过排除的测试

test{
    exclude 'com/yyj/*'
}
img
img

8.2.2 TestNG

imgimg

可以使用以下命令语法来执行一些测试任务:

gradle <someTestTask --debug-jvm

9、Gradle多项目构建

  • Gradle可以轻松处理各种大小规模的项目
    • 小项目由一个单一的构建文件和一个源代码树构成
    • 大项目可以将其拆分成更小的,相互依赖的模块,以便更容易理解,Gradle完美支持这种多项目构建的场景

9.1 settings.gradle+build.gradle

这种构建有各种形状和大小,但它们都有一些共同的特点

  • **项目的根目录或主目录**中都有一个settings.gradle文件:全局配置

    • include 各个模块
    • rootProject.nameopen in new window 根模块的名字
    • rootProject.children.each 设置每个子项目的buildFileName
      • 对应${project.name}.gradle文件,默认是build.gradle
    • settings.gradle.projectsLoaded 项目加载时的设置
      • buildScan 选择编译哪些东西
  • 根目录或主目录都有一个build.gradle文件

  • 具有自己的*.gradle构建文件的子目录(某些多项目构建可能会省略子项目构建脚本)。

要列出构建文件中的所有项目,可以使用以下命令:

D:\Coding\OnlineStudy\gradlestudy>gradle -a projects
Starting a Gradle Daemon (subsequent builds will be faster)

> Configure project :
this is the first gradle
this is the outside gradle
this is the inside gradle
y
y
j
yyj
yyj
yyj
yyj
description applied

> Task :projects

------------------------------------------------------------
Root project 'gradlestudy' - this is other gradle
------------------------------------------------------------

Root project 'gradlestudy' - this is other gradle
\--- Project ':mygradle'

To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :mygradle:tasks

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.8.3/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 6s
1 actionable task: 1 executed

9.2 Wrapper~gradle-wrapper.properties

img
img

9.3 设置

9.3.1 根目录下~settings.gradle

  • 自动写入各个模块内容
rootProject.name = 'gradlestudy'
include 'entry'
include 'service'

9.3.2 根目录下~指定常规构建设置

  • 在根项目中的build.gradle文件中,常规配置可以应用于所有项目或仅应用于子项目

    • 这指定了一个公共com.yyj组和一个0.0.1-SNAPSHOT版本到所有项目
      • Project API提供了一个属性allprojects,它返回当前项目及其下面所有子项目的列表
      • 如果使用闭包调用allprojects,则闭包的语句将委派给与所有项目相关联的项目
      • 可以使用allprojects.each进行迭代,但这将更冗长
    • subprojects闭合所有应用对子项目通用配置,但不对根项目应用
  • 其他构建系统使用继承作为定义公共行为的主要方法,Gradle也为项目提供继承

    • 但Gradle使用配置注入作为定义公共行为的常用方式,这是一种非常强大和灵活的配置多项目构建的方式,
    • 共享配置的另一种可能性是使用公共外部脚本。
// 针对多模块 打包的策略
buildscript {
    // 自定义参数
    ext {
        // 具体版本依赖可以去 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 找相应的版本
        springBootVersion = '2.3.12.RELEASE'
        springCloudVersion = 'Hoxton.SR12'
        springCloudAlibabaVersion = "2.2.7.RELEASE"
        // 依赖包
        hutoolVersion = '5.7.2'
    }

    // 项目仓库设置
    repositories {
        // 优先使用本地 mavene 仓库
        mavenLocal()
        // 阿里云 central 仓和 jcenter 仓的聚合仓
        maven { url 'https://maven.aliyun.com/repository/public/' }
        // 阿里云 gradle 插件仓库
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
        // 阿里云 spring 代理仓库
        maven { url 'https://maven.aliyun.com/repository/spring/' }
        // 中央maven仓库
        jcenter()
        mavenCentral()
    }

    // springboot gradle 打包插件依赖
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

// 所有项目配置
allprojects {
    // gradle插件
    //  Java的gradle插件 
    apply plugin: 'java'
    //  maven 扩展插件 
    apply plugin: 'maven'
    // maven发布的gradle插件
    // apply plugin: 'maven-publish'
    // idea 扩展插件 
    apply plugin: 'idea'
    // java增强 
    apply plugin: 'java-library'

    // 定义您的源文件应该被视为哪种语言版本的 Java。
    sourceCompatibility = '1.8'
    // 定义您的代码应该运行的最低 JVM 版本,即它确定编译器生成的字节码版本。
    targetCompatibility = '1.8'

    // 项目信息 
    group = 'com.gavin'
    // 版本
    version = '0.0.1-SNAPSHOT'

    // 项目仓库设置
    repositories {
        // 优先使用本地 mavene 仓库
        mavenLocal()
        // 阿里云 central 仓和 jcenter 仓的聚合仓
        maven { url 'https://maven.aliyun.com/repository/public/' }
        // 阿里云 gradle 插件仓库
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' }
        // 阿里云 spring 代理仓库
        maven { url 'https://maven.aliyun.com/repository/spring/' }
        // 自己的生产库maven仓库
        maven {
            credentials {
                username '61ce7cfea96ac5d9b038f98c'
                password 'Ywnuvi=(4e9d'
            }
            url 'https://packages.aliyun.com/maven/repository/2173289-release-vctkTy/'
        }
        // 自己的开发版库maven仓库
        // maven {
        //     credentials {
        //         username '61ce7cfea96ac5d9b038f98c'
        //         password 'Ywnuvi=(4e9d'
        //     }
        //     url 'https://packages.aliyun.com/maven/repository/2173289-snapshot-g5yEdX/'
        // }
        // 中央maven仓库
        jcenter()
        mavenCentral()
    }

    // 指定编码格式 第一种方法
    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }

    // 指定编码格式 第二种方法
    // [compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'

    // 依赖范围配置修改
    configurations {
        // 修改annotationProcessor 使其可以继承 
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

}

// 子项目设置 
subprojects {
    // springboot插件 
    apply plugin: 'org.springframework.boot'
    // spring依赖管理插件 
    apply plugin: 'io.spring.dependency-management'

    // 全局依赖
    dependencies {

        // hutool 简化工具集
        implementation "cn.hutool:hutool-core:${hutoolVersion}"

        // 热部署开发工 idea 中使用 Jrebel
        // developmentOnly 'org.springframework.boot:spring-boot-devtools'

        // 注解依赖 
        annotationProcessor(
                // 配置文件解析 
                'org.springframework.boot:spring-boot-configuration-processor',
                // lombok 简化开发 
                'org.projectlombok:lombok'
        )

        // 测试依赖
        testImplementation('org.springframework.boot:spring-boot-starter-test') {
            exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
        }
    }

    // 子项目管理依赖 
    dependencyManagement {
        imports {
            // Spring-Cloud 依赖
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
            // Spring-Alibaba 依赖
            mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${springCloudAlibabaVersion}"
        }
         // 子项目管理依赖
        dependencies {
            dependency "mysql:mysql-connector-java:8.0.25"
            dependency 'com.baomidou:mybatisplus-spring-boot-starter:1.0.5'
        }
    }

    // 测试配置 
    test {
        useJUnitPlatform()
    }
}

----------------------子模块中----------------------------
// 将子项目打成jar包
jar.enabled = true 

// 要想其不生产springboot jar 需要使其失效
bootJar.enabled = false

如只针对service执行:

img
img
img
img

9.3.3 子项目指定配置和依赖关系

  • 子项目也可以设置allProjects{}和subProjects, 针对最外层项目和最外层项目所有的子项目
  • 增加特有内容
    • 项目依赖项可使用项目方法指定

如对于entry子项目增加依赖:

img
img

如只针对service执行:

img
img

10、Gradle 部署

  • Gradle提供了几种部署构建工件(artifacts)存储库的方法
    • 将工件的签名部署到Maven仓库时,还需要签署已发布的POM文件

10.1 使用Maven插件部署

10.1.1 build

img
img

10.1.2 publish

发布到本地仓库

  • Gradle默认提供maven-publish插件,它用于发布gradle脚本
apply plugin:'java'
// 使用maven插件发布
apply plugin:'maven-publish'

publishing{
    publications{
        // 使用MavenPublication
        maven(MavenPublication){
            // 从这里进行获取源集下的编译好的文件
            from(components.java)
        }
    }

    repositories {
        maven{
            //发布到这个仓库,这里实际上是个文件夹
            url "$buildDir/repo"
        }
    }
}

imgimg

发布到远端

apply plugin:'maven-publish'

publishing{
    publications{
        maven(MavenPublication){
            from(components.java)
        }
    }

    repositories {
        maven{
            //default credentials for a nexus repository ManageReferralControl
            credentials{
                username 'admin'
                password 'mypasswd'
            }
            //发布maven存储库的url
            url "http://localhost:8080/nexus/content/repositories/releases/"
        }
    }
}

10.2 将项目从Maven转换为Gradle

  • 有一个特殊的命令用于将Apache Maven pom .xml文件转换为Gradle构建文件,如果此任务已经知道使用的所有Maven插件
img
img
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>Test02MavenSpark</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <scala.version>2.12</scala.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.spark/spark-core -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_${scala.version}</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>

</project>
D:\Coding\Test\Test02MavenSpark>gradle init --type pom
Starting a Gradle Daemon (subsequent builds will be faster)

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 2


> Task :init
Maven to Gradle conversion is an incubating feature.
Get more help with your project: https://docs.gradle.org/6.8.3/userguide/migrating_from_maven.html

BUILD SUCCESSFUL in 22s
2 actionable tasks: 2 executed
D:\Coding\Test\Test02MavenSpark>
img
img

结果build.gradle.kts

/*
 * This file was generated by the Gradle 'init' task.
 */

plugins {
    java
    `maven-publish`
}

repositories {
    mavenLocal()
    maven {
        url = uri("https://repo.maven.apache.org/maven2/")
    }
}

dependencies {
    implementation("org.apache.spark:spark-core_2.12:3.1.2")
}

group = "org.example"
version = "1.0-SNAPSHOT"
description = "Test02MavenSpark"
java.sourceCompatibility = JavaVersion.VERSION_1_8

publishing {
    publications.create<MavenPublication>("maven") {
        from(components["java"])
    }
}