分类: Gradle

  • netflix的gradle插件

    Netflix在开源界的声誉稳步上涨,主要源于其公司产品特性中抽象出的微服务体系概念落地的开源技术。NetflixOSS不管包含主要的抽象组件,也开源了它使用的gradle插件,很多插件非常易用。

    Gradle作为构建工具,有远优于Maven的配置灵活性和Groovy对于Java世界极高的亲和力。

    一个普通的模板项目一般只是用了java和对应IDE插件,比如

    apply plugin: java
    apply plugin: idea
    apply plugin: eclipse

    但是除此之外还有一些基本的,比如发布,版本号升级,项目联系人,协议检查等等等等基本配置。

    Netflix的gradle-netflixoss-project-plugin可以快速实现这些。

    buildscript {
      repositories { jcenter() }
      dependencies { classpath 'com.netflix.nebula:gradle-netflixoss-project-plugin:3.2.2' }
    }
    
    allprojects {
        apply plugin: 'nebula.netflixoss'
    }

    这个插件其实也是调用其他插件,除了协议检查使用了hierynomus的以外,其他都是 Netflix自己的。默认的协议header是Netflix的,需要自己重新配置,格式如下:

    Copyright ${year} Netflix, Inc.
    
    
  • 使用Gradle注册SpringXD的module

    使用Gradle注册SpringXD的module

    SpringXD是Pivotal的大数据产品,提供了一个抽象的数据处理平台。

    SpringXD将数据解决方案抽象为数据吸纳,分析,流调度和输出四大块。

    作为源头的数据吸纳可以从各种数据源中获取需要的数据,基于Spring的另外一个项目spring-integration,这一部分的大部分实现都可以使用简单的dsl实现。

    在SpringXD中每一个部分的组件都可以自己编写并注册到服务中,方便之后的使用。

    但是在编写阶段每次都需要打包,上传服务器,然后注册,整个过程还是有点繁琐的。

    Gradle作为一个构建工具,自然可以通过自定义任务完成这个任务。

    微博数据吸纳

    这里以微博的数据源为例。

    微博的数据源因为新浪微博提供了sdk,所以自己编写稍微方便一些。

    SpringXD项目默认也提供了twitter的两个source方便测试。

    先看一下build.gradle的配置

    ext {
    xdVersion ='1.1.1.RELEASE'
    springVersion ='4.1.3.RELEASE'
    moduleType ='source'
    moduleName ='weibo'
    xdServer ="http://192.168.0.12:9393"
    version ='0.0.1-SNAPSHOT'
    }

    最关键的配置变量是moduleType,moduleName和xdServer。

    为了简单明了,WeiboSource并不具有配置参数(一般情况下都需要提供一些配置参数的,比如apiKey),主配置文件如下

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/integration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <channel 
  • 在Gradle中限制对jar包签名时机

    Maven仓库是一个包含大量依赖库的地方,有时候我们需要发布自己的库到仓库。

    仓库虽然对于发布的库的具体功能和作用没有太多要求,但是有一些强制要求是必须的。

    发布的内容物可以是jar,aar等,但是都必须满足一下条件:

    • Metadata(pom.xml)
    • 签名
    • source jar
    • javadoc jar

    Gradle自身包含了mvn插件和signing插件,所以整个工作还是比较简单的,大体配置如下:

    signing {
    required {
    isReleaseVersion && gradle.taskGraph.hasTask("uploadArchives")
    }
    signconfigurations.archives
    }
    task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier ='javadoc'from'build/docs/javadoc'
    }
    task sourcesJar(type: Jar) {
    classifier ='sources'fromsourceSets.main.allSource
    }

    如果是快照版本就会发布到snapshot仓库,否则就是staging库。

    对于快照版本是不需要签名的,所以在操作中尽量快照版本不签名,一来是节约时间,二来是快照版本如果通过CI发布的,就可以省去很多事。

    signing插件的配置中通过指定required来决定是否跳过签名。…

  • Gradle中获取可用端口

    在项目需要用到集成测试,即打包整个项目,通过容器启动,然后直接测试。

    测试的环境不一定是稳定的,所以容器对外的端口最好是保证可用的。

    以一个Spring Boot的项目为例子,使用gretty插件来启动应用。

    gretty {
    springBoot =false
    port =7777
    integrationTestTask = 'e2eTest'
    }

    如果端口7777被占用,那么测试就会失败。

    稍微修改一下,使用AvailablePortFinder来寻找可用端口。

    AvailablePortFinderavailablePortFinder = AvailablePortFinder.createPrivate()
    IntegerhttpPort = availablePortFinder.nextAvailable
    
    gretty {
    springBoot =false
    port = httpPort
    integrationTestTask = 'e2eTest'
    }

    这样项目启动时的端口就可以保证可用性了。

    在测试中的使用也很简单,因为gretty对于集成测试的支持很好,相关属性都会写入系统属性以供测试使用。

    在测试中可以这样使用

    privatefinalstatic String 
  • 共享常用的Gradle配置片段

    Gradle灵活而强大,而且自定义简单,会Groovy用Groovy,不会或者不想学的直接写Java也可以。

    对于build.gradle而言,简单的项目还好,复杂项目这个配置就有点长了。

    虽然可以通过将Gradle Script抽成单个文件的方式来让配置更清晰,但是这样并没有做到常用配置的共享。

    因为很多配置其实是多个项目可以共用的,比如idea相关配置。

    分割配置

    当build.gradle文件越发繁琐的时候,最简单直接的方法就是将其拆分,比如idea相关配置可以拆分到 gradle目录中的idea.gradle文件中。

    apply plugin:'idea'
    
    idea {
    module {
    inheritOutputDirs =false
    outputDir =file("$buildDir/classes/main/")
    }
    
    project {
    ipr {
    withXml { provider ->
    def node = provider.asNode()
    node.component.find { it.'@name' =='VcsDirectoryMappings' }?.mapping[0].'@vcs' ='Git'
    }
    }
    }
    
  • 使用Gradle下载phantomjs

    对于Web应用开发,测试中有一个很重要的测试是Functional Test(或者叫Integration Test)。

    Functional Test除了需要相关的库以外还需要一个Driver,可以是Chrome,Firefox等等。

    因为并不是每一个开发机器或者CI服务器都有浏览器的,所以保证测试的可用性是相当重要的。

    常用的方法是将浏览器提前下载,放置在项目目录中,纳入版本管理。这样测试的运行就可以直接使用。

    但是这种方法有两个问题:

    • 将大量文件纳入了版本管理中
    • 对于不同平台还需要下载不同平台的Driver

    其实还有一个办法就是让构建工具自动下载,下载的时候可以根据平台来下载指定版本。这样即提升了易用性,也降低了切换难度。

    这里以phantomjs为例,来看看怎么让Gradle去下载平台相关的phantomjs。

    首先明确phantomjs的下载地址,在bitbucket上,https://bitbucket.org/ariya/phantomjs/downloads

    文件名是phantomjs+版本号+平台。

    首先对于平台的判断使用commons-io库来操作。

    import org.apache.tools.ant.taskdefs.condition.Os
    
    buildscript {
    repositories {
    jcenter()
    }
    dependencies {
    classpath"commons-io:commons-io:2.+"
    }
    }

    判断代码如下:

    def osFilenamePart
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
    osFilenamePart ="windows.zip"
    }elseif (Os.isFamily(Os.FAMILY_MAC)) 
  • 修改Gradle中Wrapper版本

    一直在用Gradle,它提供的wrapper是一个很实用的功能。

    可以快速切换版本,保证构建的一致性,还可以方便没有安装Gradle的用户,也能保持构建工具版本的一致性。

    启用Wrapper以后会创建一个gradle目录,其中包含一个gradle-wrapper.properties文件,内容一般如下:

    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://services.gradle.org/distributions/gradle-2.0-bin.zip

    偶尔需要修改Gradle Wrapper版本的时候我会直接修改最后一行的distributionUrl参数。

    今天看文档才发现了一个Wrapper任务,每次的修改只需要修改这个任务,然后运行就会自动创建或者修改上面那个文件了。

    task wrapper(type: Wrapper) {
    gradleVersion = '2.0'
    }

    之后运行./gradlew wrapper即可。…

  • Libgdx使用Gradle构建速度慢的问题

    Libgdx正式推出1.0版本,其中最重要的一个变化就是正式启用Gradle模板支持。

    填写必要信息后会自动生成Gradle配置文件,通过Gradle可以创建Idea和Eclipse的项目文件,更可以快速升级和添加依赖。

    但是很多人再使用的时候,特别是第一次接触Gradle,会遇到很多问题,最关键的一个就是速度慢。本文会介绍这个问题的原因和解决方法。

    Gradle Wrapper

    Gradle的Wrapper很多文章翻译为包装器。包装器的出现是基于这样的需求,即让没有装Gradle的机器上也能正常的构建你的项目。

    它和Groovy里的Grape类似。如果目标机器上没有Gradle,包装器将先下载安装合适版本的Gradle,然后再运行相应的任务。如果有,但是版本不同,它也可以保证构建工具本身的版本相同。

    出发点是好的,但是现实确实复杂的。因为默认下载的地址http://services.gradle.org/在中国访问速度很慢很慢,而且需要下载的文件大小还很大,一般有40+M,基本上是不能下载成功的。

    对于这个问题有两种解决方法:

    • 使用本地Gradle
    • 修改下载地址

    使用本地Gradle

    这种方法实质上是不使用包装器,而是通过各种方法安装Gradle,然后直接执行。注意,执行的时候不要调用gradlew [command]而是使用gradle [command]

    这种方法简单,但是不能享受到包装器的优势。

    修改下载地址

    访问Gradle Distributions的速度慢,我们可以使用一个快的。

    Wrapper任务有一个名为distributionUrl的属性,直接修改它指定新的下载地址就行了。

    可以在build.gradle中修改,比如

    task prepareWrapper(type: Wrapper) {
    gradleVersion ='1.12'
    distributionUrl ='alternative.location'
    }
  • 使用Gradle自动发布Java Web到SAE

    使用Gradle自动发布Java Web到SAE

    现在像SAE这类的应用引擎已经比较多了,百度和腾讯都提供了相似的平台。

    我很早的时候就开始用SAE,当时还为了迁就SAE学习了PHP(当时只支持PHP和另外一个什么语言)。后来SAE支持Java了,版本是6,容器是Jetty 7.4,而常用的框架也基本能跑。

    代码的部署使用svn,稍微有点麻烦。最近在做一个Java Web的练习,代码放在github上,每次上传到SAE很烦。项目使用Gradle管理,所以琢磨着怎么把自动发布到SAE这个事情交给Gradle来做。

    流程分析

    先来看一下SAE这边。

    建立默认版本,版本号为1。然后通过代码管理页面上传一个war包。

    进入svn仓库看一看

    其实就是把对应的war包放在版本号目录的根目录就可以了。

    而调用

    gradle war

    就可以生成war包,而文件地址通过以下方法获得

    war.archivePath

    这样就只需要checkout原有代码,然后将新的war拷贝过去,然后commit就行了。

    直接调用SVN命令

    Gradle有一种任务类型是Exec,可以直接在命令行调用命令。

    比如我们的checkout操作就可以这样

    task checkoutRepo(type:Exec) {
    workingDir'build/'
    commandLine'svn','checkout',repo_path,"svn"
    }

    这样代码仓库就被签出到build/svn目录下了。

    在使用copy指令

    copy{
    from war.archivePath
    into"build/svn/"+numberVersion
    }

    当然,gradle生成的war包的名字组成是

    ${baseName}-${appendix}-${version}-${classifier}.${extension}

    如果要重命名的话,可以使用rename,比如利用重命名去掉version信息

    copy {
    from war.archivePath
    into 
  • Gradle中ProGuard的配置

    好久没有写博客了…元旦前赶紧写一篇吧…

    这些日子琢磨了一下gradle。对比起maven确实在配置上灵活很多,对groovy的支持可以更容易的自定义任务。

    由于最近的几个项目中都使用到了moco这个开源项目,它使用gradle管理,使用命令gradle uberjar可以生成一个独立运行包,这个包有8M大。我使用的环境比较特殊…8M有点大了,就琢磨这使用ProGuard给它瘦个身,效果不错,简单配置以后大小变成了4.6M,只有原来的57%了。

    在配置的过程中遇到了很多难题,google之后都没有什么中文参考,故记录下了这次尝试,分享给大家。

    ProGuard简介

    ProGuard是一个压缩、优化和混淆Java 字节码文件的软件。它可以删除无用的类、字段、方法和属性。还可以删除没用的注释,优化 字节码文件。它还可以使用简短的无意义的名称来重命名已经存在的类、字段、方法和属性。

    我最开始接触ProGuard是在Android的开发中,这个工具已经成为标配了。其实ProGuard一样可以用于一般的Java项目。它的主要功能有三块:压缩,优化,混淆。其中压缩是删除没有用到的类等,当你的项目使用到了大量开源库的时候这个功能尤其明显。这也是本文主要用到的功能。优化可以去除一些无用参数,还可以进行一些代码内联。混淆功能是将包名、类名、方法名等等用无意义的字符替换掉,可以增加反编译的难度,保护你的代码。混淆也可以减少包的大小,但是混淆后不利于调试。

    ProGuard的配置

    大部分的工具都有配置,如果你没有太大的需求,一般可以直接使用。而ProGuard的配置是不可缺少的,特别是刚刚接触这个工具的时候,我觉得这个配置完全是自己写不出来的,我是针对每一个用到的包去搜索复制相关配置。后面慢慢发现其实还好,了解了原理以后就可以自己配置了。

    ProGuard会从你给出的入口点切入开始分析,一般是程序的main方法,如果某个类或者方法没有时候就会被去除。然而有时候程序中用到了某些类是通过配置文件或者反射等方法得到的,这种情况ProGuard可能就会误删。虽然目前ProGuard可以分析一些简单的情况,但是更多的时候还是需要自己配置。

    在Gradle中使用ProGuard

    ProGuard提供了Gradle插件,这样我们可以更方便的将ProGuard集成进来了。当前最新版是4.10。

    这个插件的介绍页面我死活打不开了…主要的参考也是其他项目的配置。

    先来看看如果在Gradle中生成一个独立包。这个包需要包含自身的源码、资源还有所有的第三方依赖。如果你的项目是一个多项目,那么你的独立包还应该其他需要的子项目,一般情况下配置如下:

    task uberjar(type: Jar, dependsOn: jar) {
    classifier ='standalone'
    from files(sourceSets.main.output.classesDir)
    from files(sourceSets.main.output.resourcesDir)
    fromconfigurations.runtime.asFileTree.files.collect { zipTree(it) }
    
    manifest {
    attributes'Main-Class': YOUR MAINCLASS,