1. 程式人生 > >DevOps入門(三)自動化構建工具Gradle

DevOps入門(三)自動化構建工具Gradle

一、Gradle

Gradle是一個開源的專案自動化構建工具,建立在Apache Ant 和Apache Maven概念的基礎上,並引入了基於Groovy的特定鄰域語言(DSL),而不在使用XML形式管理構建指令碼。

Groovy是用於Java虛擬機器的一種敏捷的動態語言,他是一種成熟的面向物件的程式語言,既可以用於面向物件程式設計,也可以用作純粹的指令碼語言。使用該種語言不必編寫過多的程式碼,同時又具有閉包和動態語言的其他特性。
與Java相比較,Groovy完全相容Java語法,分號是可選的,類和方法預設都是public,編譯器給屬性自動新增getter/setter方法,屬性可以直接用點號獲取,不再需要通過方法來獲取,同時最後一個表示式的值

會被作為返回值,==等同於equals(),不會有NullPointerException。
Groovy的高效特性中,自帶了assert語句,它是弱型別的程式語言,直接通過def來定義型別;同時它的括號是可選的,字串有多種寫法。

Gradle有以下作用:      
    1、 按照約定宣告構建和建設;
    2、 強大的支援多工程的構建;
    3、 強大的依賴管理(基於Apache ivy),提供強大的便利去構建工程;
    4、 權利支援已有的maven或者ivy倉庫基礎建設;
    5、 支援傳遞性依賴管理,在哪不需要遠端倉庫和pom.xml和ivy配置檔案的前提下;
    6、 基於groovy指令碼構建,其build指令碼使用groovy語言編寫;
    7、 具有廣泛的領域模型支援構建;
    8、 深度API;
    9、  易遷移;

Mac上的Gradle安裝如下:

$ brew update && brew install gradle

安裝後可以使用如下命令驗證安裝:

gradle -v

二、Gradle的目錄結構

Gradle相關的檔案和目錄結構如下:

Project-name
|--modules
    |--build.gradle
|--build.gradle
|--gradlew
|--setting.gradle

./builld.gradle 和 ./app/build.grade
gradle專案自動編譯的時候要讀取的配置檔案。比如指定專案的依賴包等。
build.grade有兩個,一個是全域性的

,一個是在模組裡面。全域性的build.grade主要設定的是宣告倉庫源gradle的版本號說明等。

buildscript {
    repositories {
        // 宣告倉庫源,比如我們構建了一個安卓的庫,現在想要把庫上傳到jcenter中供別人一起使用,則可以上傳到jcenter中
        // 具體上傳步驟見:http://www.jcodecraeer.com/a/anzhuokaifa/Android_Studio/2015/0227/2502.html
        jcenter()
    }
    dependencies {
        // 說明gradle的版本號
        classpath 'com.android.tools.build:gradle:1.3.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

// 所有專案都繼承這個配置
allprojects {
    repositories {
        mavenLocal()
        jcenter()
    }
}
在每個應用的根目錄下的build.gradle檔案中設定了模組的gradle構建配置,如下是一個工程專案的build.gradle檔案:
import org.ajoberstar.grgit.* //提供一個Grgit例項,允許與Gradle專案所在的Git倉庫互動

defineProperty("major", 2)
defineProperty("minor", 0)
defineProperty("buildNumber", "DEV")
defineProperty("type", "regression")
defineProperty("sourceMap", "true")

buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath 'org.akhikhl.gretty:gretty:1.1.8',
                'gradle.plugin.com.tools.security:dependency-check:0.0.4',
                'org.ajoberstar:gradle-git:1.1.0',
                'gradle.plugin.com.palantir:jacoco-coverage:0.4.0'
    }
}

project(":") {

    repositories {
        mavenCentral()
        maven {
            url "http://[repalce with deliveryurl]"
        }
    }

    apply plugin: 'java'
    apply plugin: 'war'
    apply plugin: 'rpm'
    apply plugin: 'xwar'
    apply plugin: 'checkstyle'
    apply plugin: "jacoco"
    apply plugin: 'com.palantir.jacoco-coverage'
    apply plugin: 'idea'
    apply plugin: 'dependency.check'
    apply plugin: org.akhikhl.gretty.GrettyPlugin

    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    [compileJava, compileTestJava]*.options.collect { options ->
        options.encoding = 'UTF-8'
    }

    dependencies {
        compile("javax.servlet:javax.servlet-api:3.1.0",
                "org.eclipse.jetty:jetty-webapp:9.2.3.v20140905",
                "org.eclipse.jetty:jetty-servlets:9.2.3.v20140905",
                'org.eclipse.jetty:jetty-util:9.2.3.v20140905',
                'org.tuckey:urlrewritefilter:4.0.4',
                "com.github.jknack:handlebars.java:4.0.4",
                "com.github.jknack:handlebars-springmvc:4.0.4",
                'com.github.jknack:handlebars-guava-cache:4.0.4',
                "org.springframework:spring-web:4.2.4.RELEASE",
                "org.springframework:spring-webmvc:4.2.4.RELEASE",
                "org.springframework:spring-aop:4.2.4.RELEASE",
                'org.springframework:spring-context:4.2.4.RELEASE',
                'org.springframework:spring-context-support:4.2.4.RELEASE',
                ...)

        testCompile('junit:junit:4.10',
                'org.hamcrest:hamcrest-all:1.1',
                'org.mockito:mockito-all:1.9.5',
                "org.springframework:spring-test:4.1.2.RELEASE")

        compile('org.owasp.esapi:esapi:2.1.0') {
            force = true
            exclude group: 'commons-beanutils'
        }
    }
    jacoco {
        toolVersion = "0.7.6.201602180812"
        reportsDir = file("$buildDir/jacocoReportDir")
    }

    jacocoTestReport {
        reports {
            xml.enabled false
            csv.enabled false
            html.destination "${buildDir}/jacoco/coverage"
        }
        afterEvaluate {
            classDirectories = files(classDirectories.files.collect {
                fileTree(
                        dir: "${buildDir}/classes/main",
                        excludes: [
                                "com/[ProjectName]/web/HomeController.class",
                                "com/[ProjectName]/web/SearchController.class",
                                "com/[ProjectName]/web/MapViewController.class",
                                ...
                        ])
            })
        }
    }

    jacocoCoverage {
        packageThreshold 0.41, LINE, "com/[ProjectName]/ancillary"
        packageThreshold 0.42, METHOD, "com/[ProjectName]/ancillary"
        packageThreshold 0.57, CLASS, "com/[ProjectName]/ancillary"

        packageThreshold 0.36, LINE, "com/[ProjectName]/content"
        packageThreshold 0.34, METHOD, "com/[ProjectName]/content"
        packageThreshold 0.60, CLASS, "com/[ProjectName]/content"
        ...
    }

    test {
        useJUnit {
            includeCategories 'com.[ProjectName].junit.UnitTests'
        }
    }

    idea {
        module {
            inheritOutputDirs = false
            outputDir = file('out')
            testOutputDir = file('out')
        }
    }

    gretty {
        servletContainer = "jetty9"
        contextPath = ""
        httpPort = 8080
        host = "0.0.0.0"
        scanInterval = 1
        fastReload = true

        integrationTestTask = "prePush"
        onStart {

            if (env == "ci" || env == "test" || env == "dev") {
                systemProperty("spring.profiles.active", "internal")
            }

            systemProperty("app.env", System.getProperty('app.env', 'development'))
            systemProperty("feature-toggle.conf", new File("src/main/conf/${type}.china-site.properties").absolutePath)
            systemProperty("china-site.conf", project.getConfigFile())
            systemProperty("log4j.configuration", "file://" + project.file("src/main/conf/log4j.properties").absolutePath)
        }

        afterEvaluate {
            prepareInplaceWebAppClasses.dependsOn(['startAssetsPipelineServer', 'copyUrlRewriteConfig'])
            jettyBeforeIntegrationTest.dependsOn(['check', 'checkJs', 'integrationTest', "jacocoTestReport", 'processAssets', ":acceptance-tests:startOmnitureServer", "acceptance-tests:clearListingsInSolr"])
            jettyAfterIntegrationTest.dependsOn([":acceptance-tests:stopOmnitureServer", "stopAssetsPipelineServer"])
        }
    }
    task integrationTest(type: Test, description: "Integration Tests.", group: "verification") {

        doFirst {
            systemProperty("china-site.conf", project.getConfigFile())
        }

        useJUnit {
            includeCategories 'com.[ProjectName].junit.IntegrationTests'
        }
    }

    task npmInstall(type: Exec, description: "Install Node Dependencies.", group: "verification") {
        commandLine "npm"
        args "install"
    }

    task stopAssetsPipelineServer(type: Exec, description: "stop assets pipeline server",
            group: "asset-pipeline", dependsOn: ['npmInstall']) {

        commandLine "node_modules/tiny-asset-pipeline/bin/main"
        args "-stop"
        ignoreExitValue true
    }

    task rpm(type: Rpm, dependsOn: 'executableWar') {
        pkg = '[project-name]'
        summary = '[Project Name]'
        version = "${major}.${minor}.${buildNumber}"
        release = "1"
        user = 'user'
        group = 'usgrp'
        splunkIndex = '[project-name]'
        service '/opt/[project-name]/service'
        require 'java-1.8.0-openjdk'

        from('src/main/conf') {
            exclude '**/*.*.properties'
            include '**/*.properties'
            into "/opt/conf/[project-name]"
        }
    }

    processResources.doFirst {
        def versionFile = new File("src/main/resources/version.properties")
        versionFile.text = "app.version = ${major}.${minor}.${buildNumber}"
        versionFile.append(System.getProperty("line.separator"))
        versionFile.append("commit=" + Grgit.open(project.file('.')).head().id)
    }
    
    task checkJs(type: Exec, description: "check JavaScript use jshint and do unit tests.", group: "verification", dependsOn: ['npmInstall']) {
        commandLine "node_modules/grunt-cli/bin/grunt"
    }

    task compressImages(type: Exec, description: "compress images(*.png) use pngquant",
            group: "asset-pipeline", dependsOn: ['npmInstall']) {
        commandLine "node"
        args "node_modules/tiny-asset-pipeline/lib/tools/compressImg.js", "src/main/webapp/assets/images/"
    }

    gradle.taskGraph.whenReady { taskGraph ->
        if (taskGraph.hasTask(prePush) || taskGraph.hasTask(integrationTest)) {
            defineProperty('env', 'test')
        } else {
            defineProperty('env', 'dev')
        }
    }

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

String getConfigFile() {

    def configFile = new File("src/main/conf/${env}.china-site.properties")
    if (!configFile.exists()) {
        configFile.createNewFile()
    }

    return configFile.absolutePath
}


void defineProperty(prop, defaultValue) {
    if (!hasProperty(prop)) {
        project.ext.set(prop, defaultValue)
    }
}
配置分為很多部分,下面會詳細介紹。

./gradle.properties
grade的執行環境配置,比如使用多少記憶體之類的。
./gradlew 和 ./gradlew.bat
自動完成 gradle 環境的指令碼,在linux和mac下直接執行gradlew會自動完成gradle環境的搭建(這兩個檔案由gradle-wrapper建立)。
./local.properties
配置SDK或者NDK的環境路徑,各個機器上這個變數可能都是不一樣的,所以不應該進入版本庫
./setting.gradle
整個專案的管理,比如這個專案包含哪些模組等。

rootProject.name = 'china-site'

include(':acceptance-tests')
project(':acceptance-tests').projectDir = new File(settingsDir, 'acceptance-tests')
./[Project-name].iml
iml是Intellij Idea的入口檔案,可以使用Idea開啟其工程。

三、Groovy

Groovy是一門jvm語言,它最終是要編譯成class檔案然後在jvm上執行,所以Java語言的特性Groovy都支援,我們完全可以混寫Java和Groovy。既然如此,那Groovy的優勢是什麼呢?簡單來說,Groovy提供了更加靈活簡單的語法,大量的語法糖以及閉包特性可以讓你用更少的程式碼來實現和Java同樣的功能。比如解析xml檔案,Groovy就非常方便,只需要幾行程式碼就能搞定,而如果用Java則需要幾十行程式碼。

3.1 Groovy的變數和方法宣告

在Groovy中,通過 def 關鍵字來宣告變數和方法,比如:

def a = 1;
def b = "hello world";
def int c = 1;

def hello() {
   println ("hello world");
   return 1;
}
在Groovy中,很多東西都是可以省略的,比如
  1. 語句後面的分號是可以省略的
  2. 變數的型別和方法的返回值也是可以省略的
  3. 方法呼叫時,括號也是可以省略的
  4. 甚至語句中的return都是可以省略的
所以上面的程式碼也可以寫成如下形式:

def a = 1
def b = "hello world"
def int c = 1

def hello() {
   println "hello world" // 方法呼叫省略括號
   1;                    // 方法返回值省略return
}

def hello(String msg) {
   println (msg)
}

// 方法省略引數型別
int hello(msg) {
   println (msg)
   return 1
}

3.2 Groovy的資料型別

Groovy中,資料型別有:

  1. Java中的基本資料型別
  2. Java中的物件
  3. Closure(閉包)
  4. 加強的List、Map等集合型別
  5. 加強的File、Stream等IO型別
型別可以顯示宣告,也可以用 def 來宣告,用 def 宣告的型別Groovy將會進行型別推斷。基本資料型別和物件這裡不再多說,和Java中的一致,只不過在Gradle中,物件預設的修飾符為public。下面主要說下String、閉包、集合和IO等。
1. String
String的特色在於字串的拼接,比如:
def a = 1
def b = "hello"
def c = "a=${a}, b=${b}"
println c

outputs:
a=1, b=hello
2. 閉包
Groovy中有一種特殊的型別,叫做Closure,翻譯過來就是閉包,這是一種類似於C語言中函式指標的東西。閉包用起來非常方便,在Groovy中,閉包作為一種特殊的資料型別而存在,閉包可以作為方法的引數和返回值,也可以作為一個變數而存在。
{ parameters ->
   code
}
閉包可以有返回值和引數,當然也可以沒有。下面是幾個具體的例子:
def closure = { int a, String b ->
   println "a=${a}, b=${b}, I am a closure!"
}

// 這裡省略了閉包的引數型別
def test = { a, b ->
   println "a=${a}, b=${b}, I am a closure!"
}

def ryg = { a, b ->
   a + b
}

closure(100, "renyugang")
test.call(100, 200)
def c = ryg(100,200)
println c
閉包可以當做函式一樣使用,在上面的例子中,將會得到如下輸出:
a=100, b=renyugang, I am a closure!
a=100, b=200, I am a closure!
300
3. List和Map

Groovy加強了Java中的集合類,比如List、Map、Set等。此處由於主要針對Gradle因此不多涉及。


4. IO

在Groovy中,檔案訪問要比Java簡單的多,不管是普通檔案還是xml檔案。Object下提供了eachLine方法:

public Object eachLine(int firstLine, Closure closure)

因此可以寫出程式碼如下
def file = new File("a.txt")
println "read file using two parameters"
file.eachLine { line, lineNo ->
   println "${lineNo} ${line}"
}

四、Gradle的編譯和生命週期

在解析 Gradle 的編譯過程之前我們需要理解在 Gradle 中非常重要的兩個物件。Project和Task。每個專案的編譯至少有一個 Project,一個 build.gradle就代表一個project,每個project裡面包含了多個task,task 裡面又包含很多action,action是一個程式碼塊,裡面包含了需要被執行的程式碼。
在編譯過程中, Gradle 會根據 build 相關檔案(一般是build.gradle),聚合所有的project和task,執行task 中的 action。因為 build.gradle檔案中的task非常多,先執行哪個後執行那個需要一種邏輯來保證。這種邏輯就是依賴邏輯,幾乎所有的Task 都需要依賴其他 task 來執行,沒有被依賴的task 會首先被執行。所以到最後所有的 Task 會構成一個 有向無環圖(DAG Directed Acyclic Graph)的資料結構。
編譯過程分為三個階段:

  1. 初始化階段:建立 Project 物件,如果有多個build.gradle,也會建立多個project.
  2. 配置階段:在這個階段,會執行所有的編譯指令碼,同時還會建立project的所有的task,為後一個階段做準備。
  3. 執行階段:在這個階段,gradle 會根據傳入的引數決定如何執行這些task,真正action的執行程式碼就在這裡.

五、Gradle初始化和引數配置

Gradle在專案中一般使用build.gradle和settings.gradle檔案配置,建立build.gradle檔案的過程如下:

1. gradle init

gradle init命令用於建立初始的build.gradle和setting.gradle檔案,執行命令如下:

$ gradle-sample gradle init
Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed
建立檔案目錄如下:


此時build.gradle和setting.gradle均為空,gradlew和gradlew.bat為Linux/Mac和Windows系統新增Gradle功能(使用方法為./gradlew [script])。

2. 配置外部引入庫

在build.gradle中使用import命令可以引入外部依賴庫,例項如下:

import org.gradle.api.tasks.Exec
import org.ajoberstar.grgit.*  /*提供一個Grgit例項,允許與Gradle專案所在的Git倉庫互動*/
3. 配置依賴專案

在build.gradle中使用apply命令可以引入依賴項,示例如下:

    apply plugin: 'java'
    apply plugin: 'war'
    apply plugin: 'rpm'
    apply plugin: 'xwar'

    apply plugin: 'checkstyle'
    apply plugin: "jacoco"
    apply plugin: 'com.palantir.jacoco-coverage'
    apply plugin: 'idea'
    apply plugin: 'dependency.check'
4. 設定maven倉庫和外部依賴

在buildscript中的repositories中配置maven專案

buildscript {
    repositories {
        jcenter()
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }

    dependencies {
        classpath 'com.reagroup.china:gradle-rpm-plugin:1.18',
                'com.reagroup.china:gradle-xwar-plugin:1.01',
                'org.akhikhl.gretty:gretty:1.1.8',
                'gradle.plugin.com.tools.security:dependency-check:0.0.4',
                'org.ajoberstar:gradle-git:1.1.0',
                'gradle.plugin.com.palantir:jacoco-coverage:0.4.0'
    }
}

也可以使用類似如下dependencies配置:

dependencies {
        compile("javax.servlet:javax.servlet-api:3.1.0",
                "org.eclipse.jetty:jetty-webapp:9.2.3.v20140905",
                "org.eclipse.jetty:jetty-servlets:9.2.3.v20140905",
                'org.eclipse.jetty:jetty-util:9.2.3.v20140905',

                'org.tuckey:urlrewritefilter:4.0.4',

                "com.github.jknack:handlebars.java:4.0.4",
                "com.github.jknack:handlebars-springmvc:4.0.4",
                'com.github.jknack:handlebars-guava-cache:4.0.4',
                "org.springframework:spring-web:4.2.4.RELEASE",
                "org.springframework:spring-webmvc:4.2.4.RELEASE",
                "org.springframework:spring-aop:4.2.4.RELEASE",
                'org.springframework:spring-context:4.2.4.RELEASE',
                'org.springframework:spring-context-support:4.2.4.RELEASE')
}


repositories中還可以配置本地倉庫和maven預設的中心倉庫:
mavenLocal
mavenCentral
此外如果url指定的倉庫需要配置密碼,也可使用
    maven {
        url "<you_company_resp_url>"
        credentials {
            username 'your_username'
            password 'your_password'
        }
    }
Gradle還可以使用本地靜態倉庫,程式碼如下:
repositories{
    flatDir{
      dirs './static_repo'
    }
}

此時在dependencies中的應用方式為:

dependencies{
  compile(name:'libraryname', ext:'./static_repo')
}


5. 配置變數

Gradle使用defineProperty函式指定變數:

defineProperty("major", 2)
defineProperty("minor", 0)
defineProperty("buildNumber", "DEV")
defineProperty("s3StaticAssets", "myfun.com.assets")
defineProperty("awsRegion", "cn-north-1")
defineProperty("s3Bucket", "myfun.stg.com.dist")
defineProperty("type", "regression")
defineProperty("sourceMap", "true")
此處定義的變數可以在後續的task中使用。
6. 配置JDK版本
sourceCompatibility = 1.8
targetCompatibility = 1.8
基本配置如上,除了如上的基本配置之外,gradle中還包括一些高階配置,以下將舉例說明。

五、Gradle配置Git

Grgit是Andrew Oberstar實現的JGit封裝器,為基於Groovy的工具與Git倉庫互動提供了更簡潔流暢的API。

  • org.ajoberstar.grgit - 提供一個Grgit例項,允許與Gradle專案所在的Git倉庫互動
  • org.ajoberstar.github-pages - 向Github倉庫的gh-pages分支釋出檔案
  • org.ajoberstar.release-base - 提供用於從專案狀態和所在Git倉庫推斷當前專案版本和建立新版本的通用結構
  • org.ajoberstar.release-opinion - 用於org.ajoberstar.release-base的預設選項,遵從語義版本控制(Semantic Versioning)
下面是一個Gradle任務示例,用於從Git倉庫克隆專案。
task cloneGitRepo(type: GitClone) {
  def destination = file("destination_folder")
  uri = "your_git_repo_uri"
  destinationPath = destination
  bare = false
  enabled = !destination.exists() //to clone only once
}

六、Gradle配置test

JUnit和TestNG允許複雜的測試方法分組。對於分組,JUnit有測試類和方法。JUnit 4.8引入了類別的概念。測試任務允許指定要包括或排除的JUnit類別。可以使用build.gradle檔案中的以下程式碼段對測試方法進行分組。如下程式碼所示:

test {
   useJUnit {
      includeCategories 'org.gradle.junit.CategoryA'
      excludeCategories 'org.gradle.junit.CategoryB'
   }
}
Test類有一個include和exclude方法。這些方法可以用於指定哪些測試應該執行。
只執行包含的測試 -
test {
   include '**my.package.name/*'
}
以下程式碼中所示的build.gradle示例檔案顯示了不同的配置選項。
apply plugin: 'java' // adds 'test' task

test {
   // enable TestNG support (default is JUnit)
   useTestNG()

   // set a system property for the test JVM(s)
   systemProperty 'some.prop', 'value'

   // explicitly include or exclude tests
   include 'org/foo/**'
   exclude 'org/boo/**'

   // show standard out and standard error of the test JVM(s) on the console
   testLogging.showStandardStreams = true

   // set heap size for the test JVM(s)
   minHeapSize = "64m"
   maxHeapSize = "512m"

   // set JVM arguments for the test JVM(s)
   jvmArgs '-XX:MaxPermSize=256m'

   // listen to events in the test execution lifecycle
   beforeTest { 
      descriptor → logger.lifecycle("Running test: " + descriptor)
   }

   // listen to standard out and standard error of the test JVM(s)
   onOutput { 
      descriptor, event → logger.lifecycle
         ("Test: " + descriptor + " produced standard out/err: " 
         + event.message )
   }
}
使用方法如下:
gradle <someTestTask> --debug-jvm

七、Gradle配置wrapper

想使用gradle wrapper,首先要在你的專案中建立。具體來說就是在build.gradle裡面加入類似於下面的task:

task wrapper(type: Wrapper) {
        gradleVersion = "2.0"
}
然後使用
gradle createWrapper  
即可生成如下目錄結構:
Project-name/  
  gradlew  
  gradlew.bat  
  gradle/wrapper/  
    gradle-wrapper.jar  
    gradle-wrapper.properties  

需要使用gradle wrapper的時候,我們就直接在專案根目錄下直接執行./gradlew(gradle wrapper的簡寫), 使用gradlew的方式和gradle一模一樣, 例如通過./gradlew tasks來檢視所有的任務。事實上,執行gradlew命令的時候,gradlew會委託gradle命令來做相應的事情,所以gradlew只是一個殼而已。

八、Gradle配置Task

任務(Task)是用於將任務定義到構建指令碼中的關鍵字。看看下面的例子,它是一個叫作 hello 的任務,將列印一個字串:hello world。將以下指令碼複製並儲存到 build.gradle 檔案中。 此構建指令碼定義一個名稱為 “hello” 的任務,用於列印hello world字串。

task hello {
   doLast {
      println 'hello world'
   }
}
可以通過為 doLast 語句指定快捷方式(表示符號 <<)來簡化此 hello 任務。如果新增這個快捷方式到上面的 hello 任務中,參考如下指令碼。
task hello << {
   println 'hello world'
}
任務依賴關係
task hello << {
    println 'Hello world!'
}
task intro(dependsOn: hello) << {
    println "I'm Gradle"
}

九、Gradle配置Jetty

gretty支援熱部署、HTTPS、轉發、除錯、自動化執行環境等諸多特性,讓開發和部署變得更加簡單。

gretty {
        servletContainer = "jetty9"
        contextPath = ""
        httpPort = 8080
        host = "0.0.0.0"
        scanInterval = 1
        fastReload = true

        integrationTestTask = "prePush"
        onStart {

            if (env == "ci" || env == "test" || env == "dev") {
                systemProperty("spring.profiles.active", "internal")
            }

            systemProperty("app.env", System.getProperty('app.env', 'development'))
            systemProperty("feature-toggle.conf", new File("src/main/conf/${type}.china-site.properties").absolutePath)
            systemProperty("china-site.conf", project.getConfigFile())
            systemProperty("log4j.configuration", "file://" + project.file("src/main/conf/log4j.properties").absolutePath)
        }

        afterEvaluate {
            prepareInplaceWebAppClasses.dependsOn(['startAssetsPipelineServer', 'copyUrlRewriteConfig'])
            jettyBeforeIntegrationTest.dependsOn(['check', 'checkJs', 'integrationTest', "jacocoTestReport", 'processAssets', ":acceptance-tests:startOmnitureServer", "acceptance-tests:clearListingsInSolr"])
            jettyAfterIntegrationTest.dependsOn([":acceptance-tests:stopOmnitureServer", "stopAssetsPipelineServer"])
        }
    }
常用屬性
  1. scanInterval:監視週期,單位為秒,設定為0等於完全關閉熱部署
  2. scanDir:需要監視的資料夾
  3. recompileOnSourceChange:監視原始碼變動,自動編譯
  4. reloadOnClassChange:編譯的類發生改變,自動載入
  5. reloadOnConfigChange:WEB-INF或META-INF發生改變
  6. reloadOnLibChange:依賴發生改變
  7. fastReload屬性,預設為true,監聽webapp/中的內容,檔案發生改變,無需重啟。