gradle学习笔记(tmp)

gradle学习笔记

优点:

  1. 支持了各种不同的依赖传递管理, 本地文件系统jar包, 还是maven, ivy的方式
  2. 是第一个构建集成工具, 可以将ant tasks, maven pom 转化成一个gradle脚本
  3. 方便移植
  4. gradle wrapper, 哪怕本地没有gradle, 也可以构建, 且还是用的设定好的版本
  5. 使用动态语言编写脚本很强大, groovy, 而不是xml, 且还有无其他好处, 等用到再体会吧
  6. 申明式的(个人感觉)

安装

jvm 参数配置, gradle 运行时的jvm参数可以通过: GRADLE_OPTS 或者是 JAVA_OPTS来设置, 且同时生效, 但是注意, JAVA_OPTS 的修改对其他java应用是共享的

基础

概念差别

Projects 和 tasks的差异

gradle的构建是由单个或者多个projects组成的, 每个projects包括许多可构建组成部分, 可以是一个jar包, 或者一个web app, 或者其他项目产生的压缩包, jar包等. 而project内部由各个tasks组成, 每个task代表了执行过程中的一个原子操作, 像编译, 打包, 生产javadoc, 发布到仓库等.

入门

定义task

task hello {
  doLast{
    println 'hello world'
  }
}
task hello {
    println 'hello'   //这是采用闭包的方式定义的task
}

groovy

采用groovy作为脚本语言, 它的语法十分简单, 在我看来又像java , 又像python , 还像scala.

class Example {
    static void main(String[] args) {
        int x = 4;
        int X = 6;
        println("sum of x and X is: " + (x+X));
    }
    
}

变量定义, 基本数据类型, 基本运算符都与java类似, 循环 不过多了个for-in, 方法的定义也差不多, 不过它对闭包的支持比java好些.

使用groovy定义gradle任务

task count << {
    4.times {println '$it'}  // 相当于 4.times { it -> println(it) }   
}

任务(task)构建

任务依赖关系

dependsOn: xxx , 且task的申明定义顺序与依赖顺序无关

task hello << {
    println 'hello'
}

task intro(dependsOn: hello) {
    println 'i am gradle'
}


延迟依赖
延迟依赖的作用是什么?

在多项目构建中, 可以让taskX在taskY之前的定义, 且taskX依赖taskY.

动态任务

什么是动态任务: 任务的行为定义是推迟的, 推迟到被选择的时候, 依据传入的参数变化

4.times { count ->
    task "task$counter" << {
        println "i am task number $counter"
    }
}

执行

> gradle -q task1
i am task number 1    //执行task1, task1的任务在被选择的时候被定义, 且行为也确定下来, 这是语言的特性还是?

任务创建后, 需要通过api进行相互之间的访问, 于是, 可以通过api , 增加任务之间的依赖, 这是否可以称之为动态依赖.

task0.dependsOn task2, task3 // 任务0,1,2,3都是上面的动态任务创建的
> gradle -q task0
i am task number 2
................ 3
................ 0

通过api给任务增加行为, 类似于python的动态添加方法以及切面行为, 比如给任务添加doFirst, doLast,分别会被添加到任务执行的开头和结尾, 当任务执行时候, 会按照特定顺序执行, 另外 << 是doLast的简写方式.

hello << {xxx}等同于 hello.doLast {xxx}
短标记法

通过 someTask.name 访问到任务的属性, 还可以通过 ext 为task增加自定义属性

task myTask {
    ext.myPro = "myPro"
}

task printSomeProp << {
    println myTask.myPro
}
调用Ant 任务

许多老的项目都是用ant构建, 或者从ant转化而来. Ant任务是gradle中的一等公民, gradle用grovvy对ant任务进行了整合, 自带AntBuilder, 这样Gradle中调用Ant任务比在 build.xml 中更方便和强大.

利用AntBuilder 创建任务, 执行任务
task loadfile << {
    def files = file('../ddddir').listFiles().sort()
    files.each { File file -> 
        if (file.isFile()) {
            ant.loadFile(srcFile: file, property: file.name)
            println " ** $file.name **"
            println "${ant.properties[file.name]}"
        }   
    }
}

gradle -q loadfile

定义默认任务

defaultTasks ..., .... 这个语法可以在build.gradle 文件的开头定义默认任务, 并且在执行的时候gradle -q 就可以, 而不用指定任务名.

DAG配置
task distribution << {
    println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << {
    println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph ->
    if (taskGraph.hasTask(release)) {
        version = '1.0'
    } else {
        version = '1.0-SNAPSHOT'
    }
}

whenReady会在已发布的任务之前影响到已发布任务的执行, 在这里发布的命令如果是distribution, 那么回事1.0-snapshot, 而如果是release, 则是1.0

实战

gradle是通用工具,通过脚本构建可以实现任意的构建

java构建

gradle已经提供了java插件来适应java程序相似的流程: 编译源码, 单元测试, 创建jar包. 且插件还为工程定义了许多默认值, 比如源码的位置等等, 而工程遵循插件的默认值会让脚本文件更加简单, 当插件不满足时, 也可以自定义插件.

使用在build.gradleapply plugin: 'java'

这样就为工程添加了java的插件, 和内置的任务. 默认值的工程结构:

project
  + build
  + src/main/java
  + src/main/resources
  + src/test/java
  + src/test/resources

Gradle 默认会从 src/main/java 搜寻打包源码,在 src/test/java 下搜寻测试源码。并且 src/main/resources 下的所有文件按都会被打包,所有 src/test/resources 下的文件 都会被添加到类路径用以执行测试。所有文件都输出到 build 下,打包的文件输出到 build/libs 下.

构建项目的任务

> gradle build
:compileJava
:processResources
:classes
:jar
:assemble
:compileTestJava
:processTestResources
:testClasses
:test
:check
:build
BUILD SUCCESSFUL

JDK在编译的时候,会或许系统的编码, 如果用的是windows系统, 可能是GBK编码, 需要在gradle中设置下:

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

参考: https://blog.csdn.net/weixin_42356453/article/details/119828358

clean

删除build目录以及所有构建完成的文件.

assemble

编译并且打包jar/war文件, 但不会执行单测.

check

编译并且测试代码, 有些插件还会增强这个任务的功能, 比如Code-quality 插件执行的CheckStyle

外部依赖

gradle集成了各种依赖传递管理的方式

maven
repositories {
    mavenCentral()   
}

其他添加依赖的方式如:

dependencies {
    compile group: xxx, name: yyyy, version: zzz
    testCompile group: xx, name: yy, version: zz
}

自定义项目

sourceCompatibility=11  // 项目源码版本, 还可以设置目标字节码版本
version= '1.0'
jar {
    manifest {
        attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
    }
}

为test添加属性

test {
    systemProperties 'proterty': 'value'
}

定义属性,添加属性, 以控制脚本行为

发布项目
uploadArchives {
    repositories {
        flatDir {
            dirs 'repos'
        }
    }
}

执行gradle uploadArchives 将jar包发布

多项目构建

需要在根目录中创建一个setting.gradle 来指明构建需要包含的项目

include "shard", "api", "services:webservice", "services:shared"

看lucene的

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}

rootProject.name = "lucene-root"

includeBuild("dev-tools/missing-doclet")

include "lucene:analysis:common"
include "lucene:analysis:icu"
include "lucene:analysis:kuromoji"
include "lucene:analysis:morfologik"
include "lucene:analysis:morfologik.tests"
include "lucene:analysis:nori"  
公共配置

多项目构建, 有些公共配置, 可以写在根目录的配置里, 子项目会迭代访问它并将其注入到自己的配置中

subprojects {
    apply plugin: 'java'
    apply plugin: 'xxxx'
    repositories {
        mavenCentral()
    }
    version = '1.0'
    dependencies {
        testComple 'junit:junit:4.11'
    }
    version = '1.0'
    jar {
      manifest.attribute provider: 'gradle'
    }

}
多项目的工程依赖

项目之间的依赖是在子项目的构建文件build.gradle 中的定义的, 比如需要先build shared, 再build api, 即api 依赖shared, 那么在api的构建文件里:

dependencies {
    compile project(':shared')
}
多项目工程的构建发布

api/build.gradle

task dist(type: zip) {
   dependsOn spiJar
   from 'src/dist'
    into('libs') {
        from spiJar.archivePath
        from configuration.runtime
    }
}

artifacts {
    archives dist
}

依赖管理基础

什么是依赖管理?

答: 一: gradle 需要知道项目构建或者运行所需要的一些文件, 以及如何找到文件, 这成为项目的依赖. 二: 项目构建完成后, 需要自动上传到某些地方, 称之为发布.

工程的依赖, 需要开发人员告诉gradle, 工程依赖什么, 他们在哪里, gradle 会帮助开发人员将它们加入到构建中, 如果在远程, 比如maven或者ivy库, 就会下载, 这个过程称之为: 依赖解决.

而依赖的自身也可能会依赖其他依赖, 这叫做: 依赖传递, gradle在构建的时候也会深入寻找它们.

最后构建完成, 需要发布到某个地方被使用, 什么需要被发布, 发布到哪里, 以什么样的形式发布出去, 这个过程叫做: 发行.

依赖配置

比如java, java的依赖, 在不同工程的不同时期可以不同, 有些只需要在编译的时候需要,有些只需要运行时有就可.

compile

编译范围依赖在所有的 classpath 中可用,同时它们也会被打包

runtime

runtime 依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要 JDBC API JAR,而只有在运行的时候才需要 JDBC 驱动实现

testCompile

测试期编译需要的附加依赖

testRuntime

测试运行期需要

不同的插件提供了不同的标准配置,你甚至也可以定义属于自己的配置项。

外部依赖

和maven类似, 需要三元组 group:name:version来定位一个依赖. 三元组前是依赖的不同阶段.

仓库

如果不使用中央仓库: mavenCentral()

repositories {
    maven {
        url "http://repo.mycompany.com/maven2"
        或者 
        url = uri("http://xxx")
    }
}
repositories {
    ivy {
        url "http://repo.mycompany.com/repo"
    }
}
repositories { // 本地
    ivy {
        // URL can refer to a local directory
        url "../local-repo"
    }
}
发布
uploadArchives {
    repositories {
        ivy {
            credential {
                username: xx
                password: uu
            }
            url "http:/......"
        }
    }
}

当发布到maven仓库时候, 语法换一下, 且需要maven插件的支持以生成对应的pom.xml

apply plugin: 'maven'
uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
        }
    }
}

todos

  1. 编写脚本
  2. 任务详细
  3. 使用文件
  4. 调用ant
  5. 构建环境
  6. java插件
  7. scala插件
  8. osgi插件
  9. checkstyle插件

你可能感兴趣的:(gradle学习笔记(tmp))