基于gradle的java项目自定义构建

项目或工作中存在的问题

  • JAVA项目开发和打包要求的环境和配置不一致,因此程序员误将开发配置上传的SVN或者GIT上之后,会替换了原生成环境配置,导致生产、测试时安装失败。不利于持续集成。通过gradle配置可以有效解决这个问题。
  • 不同的项目需要相同的打包步骤,导致编写构建代码重复,很可以引起配置不一致,导致持续集成配置复杂。通过gradle插件开发,标准化构建,方便使用,统一配管配置。
  • 项目构建后要求有固定的格式,gradle构建可以解决这个问题。

背景技术及术语解释

Gradle 构建已经相当的普遍,目前使用的spring框架已使用gradle构建。
gradle 是用groovy(Groovy是一种基于JVM的动态语言)编写工具。可以帮助团队构建,持续集成,快速交付的工具,是一种DSL,即Domain Specific Language,领域相关语言,有自己特有的术语。

Gradle特点:
  • 构建文件脚本化。可编程化,构建文件冗余少,可维护性更高。

  • 自动缓存文件信息,重新编译必要的部分,加快编译速度。

  • 可编程。定义自定义任务,满足项目定义的需要。

  • 可与其他构建工具集成(ant,maven)

  • 自动的版本管理库

  • 丰富的插件

  • 免费使用,使用apache license 2 协议。项目代码在https://github.com/gradle/gradle

  • 学习成本低,非深入定制,不需要了解内部实现机制,只要会写配置文件即可。

    gradle和ant、maven的关系和比较

    Ant:Ant是用java编写的.构建文件采用xml。 Ant的功能虽然强大,但过于灵活,规范性不足,对目录结构及build.xml没有默认约定,且没有统一的项目依赖管理(项目依赖需要和apache Ivy结合使用)。
    Maven:Maven解决了规范性的问题,依赖统一管理的问题,统一了构建了生命周期,可插件扩展功能。Maven的理念是约定大于配置,但由于规范性太强(包括生命周期),灵活性不足,pom.xml采用Xml结构,项目一大,Xml就显得冗长。
    Gradle:综合了Ant和Maven的优点,吸收了Ant中task的思想,然后把Maven的目录规范以及仓库思想也融合了进来,但允许用户自由的修改默认的规范(如,可随意修改源码目录),配置文件则采用Groovy语言来书写,Groovy是一门可编程语言,配置文件本身就可以视为一份源代码,并最终交由Gradle来处理执行。

本方案技术详细描述

案例1:

案例说明: 项目源代码(如图1所示)下有个tools文件夹,tools文件夹下有1个项目使用说明和项目启动脚本,现需要将项目打包成图2的形式,即将项目打包成jar包,并将tools下的内容构建于jar文件同一目录下,方便项目启动;并且要将src/main/resources/下的application.yml打包的时候复制到config目录下;并且为了传输方便,还得将整个项目打包成zip包。目前maven除了自己开发插件实现外,无法实现该功能,但是通过gradle可以轻松的实现。

方式一:在项目根目录的build.gradle文件内加入如下代码。
`task copyReadme(type:  Copy){`
 `from ('tools')`
 `into libsDir`
`}`

`task copyResources(type:  Copy){`
 `from ('src/main/resources/application.yml')`
`into "$libsDir/config/"`
`}`

 `task unzip(type:  Copy)  {`
`println "==============================>unzip"`
`into "$buildDir/classes/java/main"`
 `}`

`task zip(type:  Zip, dependsOn: build){`
`into ('event-simulation'){`
`from libsDir`
`}`
`}`

 `build.finalizedBy(copyReadme,copyResources)`

代码解释及原理说明:gradle构建有个接口是finalizedBy,作用是在于在构建结束时调用自定义的任务。
所以我们自定义2个task,task的格式是闭包。
闭包在groovy中是一种类型,类似与java中的lambda表达式和接口,具体请查阅groovy语言。
第一个task是复制脚本,任务的类型是复制type: Copy, 从tools文件夹复制到编译目录下的lib文件夹下。
第二个task是将application.yml文件从src/main/resources复制到编译目录下的lib文件夹下的config目录下。如果没有该目录会自动创建。
然后我们使用finalizedBy去调用他们。
最后我们创建第三个task,我们命名为zip,任务类型是Zip,dependsOn是依赖于构建,内容是将lib文件夹下的内容打包成event-simulation.zip。
那么我们如何运行呢?在项目根目录下我们运行

`gradle clean zip`

因为我们声明zip依赖与build,所以先执行build编译项目,在项目编译结束时调用上述2个方法,最后调用我们的zip方法打包。
但这种方法还是有点繁琐,在这里列举希望大家有个基本的概念,我们来看第二种实现方式。我们在第二种实现中加入新的功能:将项目的名称和版本号到我们的说明文档中。

方式二:

`apply plugin:  'distribution'`
`distributions {`
 `main {`
`archivesBaseName = baseName`
`contents {`
`from (libsDir,'tools')`
`rename (archivesBaseName +  '-'  + version, archivesBaseName)`
`into ('config')  {`
`from ('src/main/resources/application.yml')`
 `}`
 `eachFile { file ->`
`if  (file.name.startsWith('readme'))  {`
`filter{ line -> line.contains('${version}')  ? line.replace('${version}', version)  : line}`
 `}`
`}`
 `}`
`}`
`}`

方式二的目标是一样的,我们使用gradle内置的插件完成,插件的作用是在编译输出文件夹下创建distributions文件夹,并将编译后的内容进行打包成zip文件。
首先,声明使用插件apply plugin: 'distribution'
然后,我们使用插件的固定格式来定义,步骤如下:
第一步,声明变量archivesBaseName,即压缩包的名称为项目名称;
第二步,复制libsDir下的文件(编译好的jar包)和tools下的文件(脚本和readme)复制到根目录;
第三步,重命名archivesBaseName-version为压缩包名称;
第四步,将application.yml文件从src/main/resources/目录下复制到根目录的config文件夹下;
第五步,打包时过滤文件,将readme文件中含义变量${version}替换为版本目前项目中的版本号。
定义好打包内容后,最后我们运行:

 gradle clean distributions

最终得到图三的zip包,这样就可以发给第三方使用了。

案例2:

本案例的目标是因为开发文件和生成环境文件经常产生冲突,导致生成环境打包内容不符合生成环境的要求。具体如下。
原spring-boot项目在开发中使用application-dev.yml的配置文件,是否启用该文件的通过application.yml的

 `spring:`
`prifiles:`
`active: dev`

来控制,当application.yml有变动时,经常会误将改配置变更导致失败,所以我们从技术手段上防止该事情的方式。
首先,我们创建application-prod.yml作为生产环境的配置文件;
然后,我们在生产环境构建时,自动的去修改这里的配置为prod,这样可以保证每次构建都是启用application-prod.yml这个文件,
接着,由于日志文件在开发可生产环境中配置也不一致,我们一并修改。
最后,我们在构建时将开发配置文件排除在生产环境的包外。
我们在项目根目录的build.gradle加入如下代码。

ext.PROD =  'prod'
processResources {
  filteringCharset =  'UTF-8'
  String buildType = project.getProperties().get('buildType')
  if  (buildType == PROD){
    eachFile {file ->
    if(file.name ==  'application.yml')  {
      filter { line -> line.contains('active')  ? line.replace('dev','prod')  : line }
    }
  if(file.name ==  'logback-spring.xml')  {
  filter { line -> line.contains('logs')  ? line.replace('logs','${catalina.base}/logs')  : line }
}

}
exclude 'application-dev.yml'
}
}

首先,我们新建一个变量,变量名称是PROD,当构建时,如果改变量名称为prod时,按生产环境的方式构建。
然后,我们声明查询的字符集是UTF-8;
接着,从命令行获取buildType参数,当此参数等于prod时,执行生产环境构建,
第一步,在过滤文件时获取名称为application.yml,并修改配置,
第二步,在过滤文件时获取名称为logback-spring.xml的日志配置文件,替换其中的变量,
第三步,排除application-dev.yml
最后,我们在生产环境的自动化构建时,执行如下命令

1.  `gradle clean build -x test -P buildType=prod`

到此我们将生成环境和开发环境进行了彻底的分割,再也不用担心误传导致的构建失败了。

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