Gradle简介和使用

Gradle的使用

内容来自实战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(typeWrapper){
  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?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值