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可以创建新的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和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?