Gradle简介和使用

Gradle的使用

个人博客 http://blog.csdn.net/qq_22329521/article/details/52712705
内容来自实战Gradle,提供的例子https://github.com/bmuschko/gradle-in-action-source
Gradle包装器
--
在机器上没有安装Gradle运行时的情况下运行Gradle构建,那就是:Gradle包装
。它也是让构建脚本运行在一个指定的Gradle版本上,它通过自动从中心仓库下载Gradle运行,解压和使用来实现。最终效果是是创建一个和系统无关的gradle版本,而且统一项目所使用的Gradle版本。

在项目中配置包装器,你只需要做两件事情:创建一个包装器任务和执行任务生成包装器文件。为了能够让项目可以下载压缩过的Gradle运行时文件,定义一个类型为 Wrapper 的任务,通过gradleVersion属性指定你想要使用的Gradle版本:

//在build.gradle 下创建
task wrapper(type:Wrapper){
  gradleVersion='1.7'
}
/*运行gradle warpper 命令, 会下载 到gradle/wapper 目录下
gradle-wrapper 是Gradle包装器微类库包含下载和解包Gradle运行时的逻辑
gradle-wrapper.properties 是包装器元信息包含已下载Gradle运行时的储存位置

和原始URL*/

使用包装器
在项目下找到gradle.bat 。使用它运行构建和使用已安装的Gradle运行时运行构建是一样的
定制包装器
某些企业有非常严格的安全策略,特别是当你为政府机构工作时,访问外网是禁止的。在这种情况下,如何让你的项目使用Gradle包装器呢?重新配置。你可以改变默认配置,将它指向一个存有运行时发布文件的企业内部服务器。同时你还可以改变本地的存储路径

task wrapper(type:Wrapper){
  gradleVersion = '1.2'        //Gradle版本号
  distributionUrl = ' //获取Gradle包装器的URL 
  distributionPath = 'gradle-dists'  //包装器被解压缩后存放的相对路径
}

Gradle基本原理

每个Gradle构建都包含三个基本构建快:project、task和property。每个构建块都包含至少一个project,进而又包含一个或多个task。project和task暴露的属性可以用来控制构建。
project
--
一个项目(project)代表一个正在构建的组件(比如,一个JAR文件),或一个想要完成的目标,如部署应用程序。每个Gradle构建脚本至少定义一个项目。当构建进程启动后,Gradle基于build.gradle中的配置实例化org.gradle.api.Project类,并且能够通过project变量使其隐式可用。Gradle构建的主要入口点


project

一个project可以创建新的task,添加依赖关系和配置,并应用插件和其他的构建脚本。它的许多属性可以入name 和description能通过get和set方法访问

version = '0.1-SNAPSHOT'

task printVersion {
    group = 'versioning'
    description = 'Prints project version.'

    doLast {
        logger.quiet "Version: $version"
    }
}

//在不显示使用project变量的情况下设置项目描述

Task重要功能

1 . 任务动作:定义一个当前任务执行时最小的工作单元。可以简单的打印“Hello World"也可以编译Java源代码
2 . 任务依赖: 将一个任务运行时需要另一个task的输出作为输入来完成自己的动作

`task

每个Task和Project实例都提供通过getter和setter方法访问的属性。也支持扩展属性

project.ext.myProp = 'myValue'

ext {
    someOtherProp = 123
}

assert myProp == 'myValue'
println project.someOtherProp
ext.someOtherProp = 567

//可支持在gradle.properties文件中声明然后进行访问

声明Task

version = '0.1-SNAPSHOT'

task first << { println "first" }
task second << { println "second" }

task printVersion(dependsOn: [second, first]) << {
    logger.quiet "Version: $version"
}

task third << { println "third" }
third.dependsOn('printVersion')     

<<是doLast的快捷版本 dependsOn 是处理task的依赖关系

终结器(相当于finally)

task first << { println "first" }
task second << { println "second" }
first.finalizedBy second

添加任意代码和配置


ext.versionFile = file('version.properties')//提供file方法 
//此处没有>>这种符号 是task配置模块
//gradle的声明周期是 初始化阶段,配置阶段,执行阶段
task loadVersion {
    project.version = readVersion()//最终调用toString的方法
}

ProjectVersion readVersion() {
    logger.quiet 'Reading the version file.'

    if (!versionFile.exists()) {
        throw new GradleException("Required version file does not exist: $versionFile.canonicalPath")
    }

    Properties versionProps = new Properties()

    versionFile.withInputStream { stream ->//读取InputStream
        versionProps.load(stream)
    }

    new ProjectVersion(versionProps.major.toInteger(), versionProps.minor.toInteger(), versionProps.release.toBoolean())
}

task printVersion << {
    logger.quiet "Version: $version"
}

class ProjectVersion {
    Integer major
    Integer minor
    Boolean release

    ProjectVersion(Integer major, Integer minor) {
        this.major = major
        this.minor = minor
        this.release = Boolean.FALSE
    }

    ProjectVersion(Integer major, Integer minor, Boolean release) {
        this(major, minor)
        this.release = release
    }

    @Override
    String toString() {
        "$major.$minor${release ? '' : '-SNAPSHOT'}"
    }
}

Input和Output

task makeReleaseVersion(group: 'versioning', description: 'Makes project a release version.') {
    inputs.property('release', version.release)
    outputs.file versionFile

    doLast {
        version.release = true
        ant.propertyfile(file: versionFile) {
            entry(key: 'release', type: 'string', operation: '=', value: 'true')
        }
    }
}

自定义Task

class ReleaseVersionTask extends DefaultTask {
    @Input Boolean release //通过注解来声明task的输入和输出
    @OutputFile File destFile

    ReleaseVersionTask() {
        group = 'versioning'
        description = 'Makes project a release version.'
    }

    @TaskAction
    void start() {
        project.version.release = true
        ant.propertyfile(file: destFile) {
            entry(key: 'release', type: 'string', operation: '=', value: 'true')
        }
    }
}

依赖管理

不完善的依赖管理技术

  • 手动将JAR文件拷贝到开发机器上。这种处理依赖关系是最原始、非自动化而且最容易出错的方式
  • 使用JAR文件共享存储器(比如,一个共享网络驱动器的文件夹),它被安装在开发人员的机器上,或者通过FTP检索二进制文件。这种方式需要开发人员建立二进制仓库的连接。新的依赖关系需要在有写权限和访问许可的情况下手动进行添加。
  • 检查所下载的JAR文件,使其和版本控制系统中的项目源代码符合。这种方法不需要任何额外的设置,只需要将源代码和依赖绑定在一起。当更新仓库中的本地副本时,整个团队都可以检索到变化。缺点是一些不必要的二进制文件占用了仓库的大量空间。只要源代码发生变化。类库副本的变化就需要频繁地检入。如果你正在开发的多个项目彼此互相依赖,就更是如此了.

外部依赖

//自定义配置,通过名字定义一个新的配置
configurations {
    cargo {
        description = 'Classpath for Cargo Ant tasks.'//设置描述
        visible = false//设置描述是否可见
    }
}
ext.cargoGroup = 'org.codehaus.cargo'
ext.cargoVersion = '1.3.1'

//依赖声明中使用map形式包含group、name和version属性
dependencies {
    cargo group: cargoGroup, name: 'cargo-core-uberjar', version: cargoVersion
    cargo "$cargoGroup:cargo-ant:$cargoVersion"
}

repositories {
    mavenCentral()
}

排除传递依赖如果遇到维护性很差的依赖,可以完全控制传递性依赖,有选择的排除某些依赖

dependencies {
    cargo('org.codehaus.cargo:cargo-ant:1.3.1') {
        exclude group: 'xml-apis', module: 'xml-apis'
    }
    cargo 'xml-apis:xml-apis:2.0.2'
}

//排除所以传递性的依赖
dependencies {
    cargo('org.codehaus.cargo:cargo-ant:1.3.1') {
        transitive=false
    }
}

动态版本声明

//声明最新版本的依赖
dependencies {
    cargo 'org.codehaus.cargo:cargo-ant:1.+'
}

少用。可靠和可重复的构建才是最重要的

文件依赖

//从仓库中获取以来然后拷贝到用户home目录下的libs/cargo子目录
task copyDependenciesToLocalDir(type: Copy) {
    from configurations.cargo.asFileTree
    into "${System.properties['user.home']}/libs/cargo"
}
//将文件以来到项目中
dependencies {
    cargo fileTree(dir: "${System.properties['user.home']}/libs/cargo", include: '*.jar')
}

仓库

仓库分为 Maven仓库 lly仓库和扁平的目录查看
Maven仓库
--
Maven仓库是java项目中最常用的仓库类型之一。类库通常是以JAR文件的形式表现。
Maven Central是构建中经常使用的仓库。Gradle想尽可能地被构建开放人人员使用,因此Gradle提供了一种快捷方式来声明Maven Central.而不必每次要定义URL http://repo1.maven.org/maven2 ,可以直接调用mavenCentral()方法

repositories {
    mavenCentral()
}

当Gradle获取以来时,它会定位仓库,下载并储存在本地缓存中。这个缓存在本地文件系统中的位置与Maven储存所下载的工作的目录是不同的。如果你在处理一个使用maven生成类库的项目,另一个Gradle项目也想使用这个类库。在开发阶段,需要检查实现周期的变化,并且要应用这些变化,为了防止每次小小的改动都必须将类库发布到远程maven仓库,Gradle 提供了本地maven仓库

repositories {
    mavenLocal()
}

自定义仓库

repositories {
    maven {
        name 'Custom Maven Repository'
        url 'http://repository-gradle-in-action.forge.cloudbees.com/release/'
    }
}

应对版本冲突

当遇到版本冲突让构建失败,运行项目的任何task都会显示版本冲突信息

configurations.cargo.resolutionStrategy{
  failOnVersionConflict()
}

强制指定一个版本

确保所有项目中使用同一个版本的类库

configurations.cargo.resolutionStrategy{
  force 'xxxx.1.3.0'
}

多项目依赖

allprojects {
    group = 'com.manning.gia'
    version = '0.1'
}

subprojects {
    apply plugin: 'java'
}

project(':repository') {
    dependencies {
        compile project(':model')
    }
}

project(':web') {
    apply plugin: 'war'
    apply plugin: 'jetty'

    repositories {
        mavenCentral()
    }

    dependencies {
        compile project(':repository')
        providedCompile 'javax.servlet:servlet-api:2.5'
        runtime 'javax.servlet:jstl:1.1.2'
    }
}

单元测试

JUnit测试

public class InMemoryToDoRepositoryTest {
    private ToDoRepository inMemoryToDoRepository;

    @BeforeClass
    public void setUp() {
        inMemoryToDoRepository = new InMemoryToDoRepository();
    }

    @Test
    public void testToDoItem() {
        ToDoItem newToDoItem = new ToDoItem();
        newToDoItem.setName("Write unit tests");
        Long newId = inMemoryToDoRepository.insert(newToDoItem);
        assertNotNull(newId);

        ToDoItem persistedToDoItem = inMemoryToDoRepository.findById(newId);
        assertNotNull(persistedToDoItem);
        assertEquals(newToDoItem, persistedToDoItem);
    }
}

dependencies {
    testCompile 'org.testng:testng:6.8'
}

代码质量管理和检测

监测代码质量不只有代码覆盖率分析。每个团队或者组织都有自己的代码规范标准,这个标准包括从简单的代码格式方面,如空格的使用和缩进,到编程最佳实践。遵循这些规范,会使代码对于其他团队成员来说更加可读,从而提高其可维护性。
在java中,可以使用广泛的开源工具或者商业解决方案,比如Checkstyle,PMD,Cobertura,FindBugs和Sonar。大多数这些工具都已Gradle核心插件或者第三方插件来使用。并且无缝地集成到构建中
代码分析工具的几个度量度

  • 代码覆盖率
  • 代码标准的遵守情况
  • 不好的编码实践和设计问题
  • 过度复杂、重复、强耦合的代码

代码覆盖率

覆盖率的标准

  • 分支覆盖率:衡量可能被执行的分支(如if/else分支逻辑)的执行情况
  • 语句覆盖率:衡量代码块中那些语句被执行了
  • 方法覆盖率:衡量执行测试的时候进入了哪些方法
  • 复杂度度量:包、类和方法的圈复杂度(代码块中独立的分支数)
    检测代码覆盖率的工具如 JacCoCo
buildscript {
    repositories {
        mavenCentral()
    }  
dependencies {
//从MavenCentral获取JaCoCo插件添加到构建脚本的classpath中
        classpath 'org.ajoberstar:gradle-jacoco:0.3.0'
    }
}
apply plugin: org.ajoberstar.gradle.jacoco.plugins.JacocoPlugin//按类型应用插件
jacoco {
    integrationTestTaskName = 'integrationTest'//定义集成测试的task名字,用于为集成测试 生成代码覆盖率报告
}

在其他项目中引入这个脚本插件。在构建后有个html文件就可以查看

allprojects {
    apply plugin: 'idea'
    group = 'com.manning.gia'
    version = '0.1'
}
subprojects {
    apply plugin: 'java'
    apply from: "$rootDir/gradle/jacoco.gradle"

    repositories {
        mavenCentral()
    }
}

参考文章
实战Gradle
https://my.oschina.net/fhd/blog/522382?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,397评论 25 707
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • 轻轻合上《白夜行》心里说不出的怅然,就像缕缕白烟从茶杯中升起,却闻不出是何种茶香。 一直觉得雪穗总是摆着...
    忘忧人Candy阅读 261评论 2 5
  • script追加新元素 script全选全不选 script获取table中的row元素 并设置style 省市选...
    Touchs阅读 166评论 0 2