程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 簡述Gradle在大型Java項目上的應用

簡述Gradle在大型Java項目上的應用

編輯:關於JAVA

在Java構建工具的世界裡,先有了Ant,然後有了Maven。Maven的CoC[1]、依賴管理以及項目構建規則重用性等特點,讓Maven幾乎成為Java構建工具的事實標准。然而,冗余的依賴管理配置、復雜並且難以擴展的構建生命周期,都成為使用Maven的困擾。

Gradle作為新的構建工具,獲得了2010 Springy大獎,並入圍了2011的Jax最佳Java技術發明獎。它是基於Groovy語言的構建工具,既保持了Maven的優點,又通過使用Groovy定義的DSL[2],克服了 Maven中使用XML繁冗以及不靈活等缺點。在Eugene Dvorkin撰寫的文章《最讓人激動的5個Java項目》中,他是這樣介紹Gradle的:

“工程自動化是軟件項目成功的必要條件,而且它應該實現起來簡單、易用、好玩。構建沒有千篇一律的方法,所以Gradle沒有死板的強加方法於我們,盡管你會認為查找和描述方法很重要,然而Gradle對於如何描述有著非常好的支持。我不認為工具能夠拯救我們,但是Gradle能給你所需要的自由,你可以利用Gradle構建易描述的、可維護的、簡潔的、高性能項目”。

在最近半年裡,我在使用Gradle作為構建腳本的大型Java項目上工作,更深切體會到Gradle在項目構建過程中是如此的簡單、易用。

1. 多Module的項目

Hibernate項目負責人Steve Ebersole在Hibernate將構建腳本從Maven換成Gradle時,專門寫了一篇文章《Gradle: why?》,文中提到Maven的一個缺點就是:Maven不支持多module的構建。在Micro-Service[3]架構風格流行的今天,在一個項目裡面包含多個Module已成為一種趨勢。Gradle天然支持多module,並且提供了很多手段來簡化構建腳本。在Gradle中,一個模塊就是它的一個子項目(subproject),所以,我使用父項目來描述頂級項目,使用子項目來描述頂級項目下面的模塊。

1.1 配置子項目

在多模塊的項目中,Gradle遵循慣例優於配置 (Convention Over Configuration)原則。

在父項目的根目錄下尋找settings.gradle文件,在該文件中設置想要包括到項目構建中的子項目。在構建的初始化階段(Initialization),Gradle會根據settings.gradle 文件來判斷有哪些子項目被include到了構建中,並為每一個子項目初始化一個Project對象,在構建腳本中通過project(‘:sub-project-name’)來引用子項目對應的Project對象。

通常,多模塊項目的目錄結構要求將子模塊放在父項目的根目錄下,但是如果有特殊的目錄結構,可以在settings.gradle文件中配置。

我所在的項目包括:

一個描述核心業務的core模塊

一個遺留的Enterprise Java Bean(enterprise-beans)模塊

兩個提供不同服務的Web項目(cis-war和admin-war)

一個通過schema生成jaxb對象的jaxb項目以及一個用來用來打ear包的ear項目

一個用於存放項目配置文件相關的config子目錄。它不是子模塊,所以 config不應該被加到項目的構建中去。

它們都放置在根項目目錄下。我們通過如下的settings.gradle來設置項目中的子項目:

include 'core', 'enterprise-beans', 'cis-war', 'admin-war', 'jaxb', 'ear'

我們將需要加入到項目構建中的子項目配置在settings.gradle文件中,而沒有加入不需要的config子目錄。

1.2 共享配置

在大型Java項目中,子項目之間必然具有相同的配置項。我們在編寫代碼時,要追求代碼重用和代碼整潔;而在編寫Gradle腳本時,同樣需要保持代碼重用和代碼整潔。Gradle 提供了不同的方式使不同的項目能夠共享配置。

allprojects:allprojects是父Project的一個屬性,該屬性會返回該Project對象以及其所有子項目。在父項目的build.gradle腳本裡,可以通過給allprojects傳一個包含配置信息的閉包,來配置所有項目(包括父項目)的共同設置。通常可以在這裡配置IDE的插件,group和version等信息,比如:

allprojects {
    apply plugin: 'idea'
    }

這樣就會給所有的項目(包括當前項目以及其子項目)應用上idea插件。

subprojects:subprojects和allprojects一樣,也是父Project的一個屬性,該屬性會返回所有子項目。在父項目的build.gradle腳本裡,給 subprojects傳一個包含配置信息的閉包,可以配置所有子項目共有的設置,比如共同的插件、repositories、依賴版本以及依賴配置:

subprojects {
    apply plugin: 'java'
    repositories {
        mavenCentral()
    }
    ext {
          guavaVersion = ’14.0.1’
          junitVersion = ‘4.10’ 
   } 
 
    dependencies {
        compile(
                “com.google.guava:guava:${guavaVersion}”
        )
        testCompile(
                “junit:junit:${junitVersion}”
        )
    }
}

這就會給所有子項目設置上java的插件、使用mavenCentral作為 所有子項目的repository以及對Guava[4]和JUnit的項目依賴。此外,這裡還在ext裡配置依賴包的版本,方便以後升級依賴的版本。

configure:在項目中,並不是所有的子項目都會具有相同的配置,但是會有部分子項目具有相同的配置,比如在我所在的項目裡除了cis-war和admin-war是web項目之外,其他子項目都不是。所以需要給這兩個子項目添加war插件。Gradle的configure可以傳入子項目數組,並為這些子項目設置相關配置。在我的項目中使用如下的配置:    

configure(subprojects.findAll {it.name.contains('war')}) {
    apply plugin: 'war'
    }

configure需要傳入一個Project對象的數組,通過查找所有項目名包含war的子項目,並為其設置war插件。

1.3 獨享配置

在項目中,除了設置共同配置之外, 每個子項目還會有其獨有的配置。比如每個子項目具有不同的依賴以及每個子項目特殊的task等。Gradle提供了兩種方式來分別為每個子項目設置獨有的配置。

在父項目的build.gradle文件中通過project(‘:sub-project-name’)來設置對應的子項目的配置。比如在子項目core需要Hibernate的依賴,可以在父項目的build.gradle文件中添加如下的配置:    

project(‘:core’) {
      ext{
                   hibernateVersion = ‘4.2.1.Final’
      }
	dependencies { 
    		compile “org.hibernate:hibernate-core:${hibernateVersion}”
}
}

注意這裡子項目名字前面有一個冒號(:)。 通過這種方式,指定對應的子項目,並對其進行配置。

我們還可以在每個子項目的目錄裡建立自己的構建腳本。在上例中,可以在子項目core目錄下為其建立一個build.gradle文件,並在該構建腳本中配置core子項目所需的所有配置。例如,在該build.gradle文件中添加如下配置:    

 ext{
       hibernateVersion = ‘4.2.1.Final’
      }
	dependencies { 
    	compile “org.hibernate:hibernate-core:${hibernateVersion}”
}

 

根據我對Gradle的使用經驗,對於子項目少,配置簡單的小型項目,推薦使用第一種方式配置,這樣就可以把所有的配置信息放在同一個build.gradle文件裡。例如我同事鄭晔的開源項目moco。它只有兩個子項目,因而就使用了第一種方式配置,在項目根目錄下的build.gradle文件中設置項目相關的配置信息。但是,若是對於子項目多,並且配置復雜的大型項目,使用第二種方式對項目進行配置會更好。因為,第二種配置方式將各個項目的配置分別放到單獨的build.gradle文件中去,可以方便設置和管理每個子項目的配置信息。

1.4 其他共享

在Gradle中,除了上面提到的配置信息共享,還可以共享方法以及Task。可以在根目錄的build.gradle文件中添加所有子項目都需要的方法,在子項目的build.gradle文件中調用在父項目build.gradle腳本裡定義的方法。例如我定義了這樣一個方法,它可以從命令行中獲取屬性,若沒有提供該屬性,則使用默認值:

def defaultProperty(propertyName, defaultValue) {
    return hasProperty(propertyName) ? project[propertyName] : defaultValue
}

注意,這段腳本完全就是一段Groovy代碼,具有非常好的可讀性。

由於在父項目中定義了defaultProperty方法,因而在子項目的build.gradle文件中,也可以調用該方法。

2. 環境的配置

為了方便地將應用部署到開發、測試以及產品等不同環境上, Gradle提供了幾種不同的方式為不同的環境打包,使得不同的環境可以使用不同的配置文件。此外,它還提供了簡單的方法,使得我們能夠便捷地初始化數據庫 。

2.1 Properties配置

要為不同的環境提供不一樣的配置信息,Maven選擇使用profile,而Gradle則提供了兩種方法為構建腳本提供Properties配置:

第一種方式是使用傳統的properties文件, 然後在使用Gradle時,通過傳入不同的參數加載不同的properties文件。例如,我們可以在項目中提供development.properties、test.properties和production.properties。在項目運行時,使用-Pprofile=development來指定加載開發環境的配置。構建腳本中加載properties文件的代碼如下:

ext {
    profile = project['profile']
}
def loadProperties(){
    def props = new Properties()
    new File("${rootProject.projectDir}/config/${profile}.properties")
            .withInputStream {
                stream -> props.load(stream)
            }
    props
}

在運行腳本的時候,傳入的-Pprofile=development可以指定使用哪個運行環境的配置文件。代碼中使用了project['profile']從命令行裡讀取-P傳入的參數,Gradle會去父項目根目錄下的config文件夾中需找對應的properties文件。

另外一種方式就是使用Groovy的語法,定義可讀性更高的配置文件。比如可以在項目中定義config.groovy的配置文件,內容如下:

environments {
    development {
        jdbc {
            url = 'development'
            user = 'xxxx'
            password = 'xxxx'
        }
    }
 
    test {
        jdbc {
            url = 'test'
            user = 'xxxx'
            password = 'xxxx'
        }
    }
 
    production {
        jdbc {
            url = 'production'
            user = 'xxxx'
            password = 'xxxx'
        }
    }
}

這裡定義了三個環境下的不同數據庫配置,在構建腳本中使用如下的代碼來加載:

ext {
    profile = project['profile']
}
 
def loadGroovy(){
    def configFile = file('config.groovy')
    new ConfigSlurper(profile).parse(configFile.toURL()).toProperties()
}

這裡在ConfigSlurper的構造函數裡傳入從命令行裡取到的-P的參數。調用loadGroovy方法就可以加載項目根目錄下的config.groovy文件,並作為一個Map返回,這樣就可以通過jdbc.url來獲取url的值。

從可讀性以及代碼整潔(配置文件也需要代碼整潔)而言,我推薦使用第二種方式來配置,因為這種方法具有清晰的結構。如上面的例子,就可以把數據庫相關的信息都放在jdbc這個大的節點下,而不用像properties文件這樣的扁平結構。但是對於一些已經使用properties文件來為不同環境提供配置信息的遺留項目裡,使用properties文件也沒有問題。

2.2 替換

通過不同的方式加載不同環境的配置後,就需要把它們替換到有占位符的配置文件中去。在配置文件中使用@key@來標注要被替換的位置,比如在config文件夾中有jdbc.properties文件,其內容如下:

[email protected]@
[email protected]@
[email protected]@

在Gradle構建過程中,有一個processResources的Task,可以修改該Task的配置,讓其在構建過程中替換資源文件中的占位符:

processResources {
    from(sourceSets.main.resources.srcDirs) {
        filter(org.apache.tools.ant.filters.ReplaceTokens,
                		tokens: loadGroovyConfig()
)
    }
}

上面這種做法用來處理子項目src/main/resources文件夾下的資源文件,所以需要將這段代碼放在子項目的獨立配置文件裡。

在一些復雜的項目中,經常會把配置文件放置到一個目錄進行統一管理。比如在我所在的項目,就專門提供了一個config子目錄,裡面存放了所有的配置信息。在處理這些資源文件時, Gradle默認提供的processResources就不夠用了,我們需要在Gradle腳本中定義一個Task去替換這些包含占位符的配置文件,然後讓package或者deploy的Task依賴這個Task。該Task的代碼如下:

task replace(type: Sync) {
            def configHome = "${project.rootDir}/config"
 
    from(configHome) {
        include '**/*.properties'
        include '**/*.xml'
        filter org.apache.tools.ant.filters.ReplaceTokens, 
tokens: loadGroovyConfig()
    }
    into "${buildDir}/resources/main"
}

這裡定義了一個Sync類型的Task,會將父項目的根目錄下的config文件夾的所有properties和xml文件使用從loadGroovyConfig()方法中加載出來的配置替換,並將替換之後的文件放到build文件夾下的resource/main目錄中。再讓打包的Task依賴這個Task,就會把替換之後的配置文件打到包中。

2.3 更復雜的情況

上面介紹了在項目中如何使用Gradle處理 properties和xml文件中具有相同配置,但其中的一些值並不相同的情況 。然而,在有些項目中不同的環境配置之間變化的不僅是值,很有可能整個配置文件都不相同;那麼,使用上面替換的處理方式就無法滿足要求了。

在我所在的項目中,我們需要依賴一個外部的Web Service。在開發環境上,我們使用了Stub來模擬和Web Service之間的交互,為開發環境提供測試數據,這些數據都放置在一個Spring的配置文件中;而在測試和產品環境上,又要使用對應的測試和產品環境的Web Service。這時,開發、測試與產品環境的配置完全不同。對於這種復雜的情況,Gradle可以在構建過程中為不同的環境指定不同的資源文件夾,在不同的資源文件夾中包含不同的配置文件。

例如,在我們項目的config目錄下包含了application文件夾,定義了不同環境所需的不同配置文件,其目錄結構如下圖所示:

在構建腳本中,根據從命令行讀入的-P參數,使用不同的資源文件夾,其代碼如下:

sourceSets {
    main {
        resources {
            srcDir "config/application/spring/${profile}", 
                        "config/application/properties/${profile}"
        }
    }
}

這樣在打包的過程中,就可以使用-P傳入的參數的資源文件夾下面的properties和xml文件作為項目的配置文件。

2.4 初始化數據庫

在項目開發過程中,為了方便為不同環境構建相同的數據庫及數據,我們通常需創建數據庫的表以及插入一些初始化數據。Gradle目前沒有提供相關的Task或者Plugin,但是我們可以自己創建Task去運行SQL來初始化各個環境上的數據庫。

前面也提到Gradle是Groovy定義的DSL,所以我們可以在Gradle中使用Groovy的代碼來執行SQL腳本文件。在Gradle腳本中,使用Groovy加載數據庫的Driver之後,就可以使用Groovy提供的Sql類去執行SQL來初始化數據庫了。代碼如下:

groovy.sql.Sql oracleSql = 
	Sql.newInstance(props.getProperty('database.connection.url'),
                props.getProperty('database.userid'),
                props.getProperty('database.password'),
                props.getProperty('database.connection.driver'))
 
try {
        new File(script).text.split(";").each {
            logger.info it
            oracleSql.execute(it)
        }
    } catch (Exception e) { }

這段代碼會初始化執行SQL的groovy.sql.Sql對象,然後按照分號(;)分割SQL腳本文件裡的每一條SQL並執行。對於一些必須運行成功的SQL文件,可以在catch塊裡通過拋出異常來中止數據庫的初始化。需要注意的是需要將數據庫的Driver加載到ClassPath裡才可以正確地執行。

因為在Gradle中包含了Ant,所以我們除了使用Groovy提供的API來執行SQL之外,還可以使用Ant的sql任務來執行SQL腳本文件。但若非特殊情況,我並不推薦使用Ant任務,這部分內容與本文無關,這裡不再細述 。

3. 代碼質量

代碼質量是軟件開發質量的一部分,除了人工代碼評審之外,在把代碼提交到代碼庫之前,還應該使用自動檢查工具來自動檢查代碼,來保證項目的代碼質量。下面介紹一下Gradle提供的支持代碼檢查的插件 。

3.1 CheckStyle

CheckStyle是SourceForge下的一個項目,提供了一個幫助JAVA開發人員遵守某些編碼規范的工具。它能夠自動化代碼規范檢查過程,從而使得開發人員從這項重要卻枯燥的任務中解脫出來。Gradle官方提供了CheckStyle的插件,在Gradle的構建腳本中只需要應用該插件:

apply plugin: 'checkstyle'

默認情況下,該插件會找/config/checkstyle/checkstyle.xml作為CheckStyle的配置文件,可以在checkstyle插件的配置階段(Configuration) 設置CheckStyle的配置文件:

checkstyle{
configFile = file('config/checkstyle/checkstyle-main.xml')
}

還可以通過checkstyle設置CheckStyle插件的其他配置。

3.2 FindBugs

FindBugs 是一個靜態分析工具,它檢查類或者 JAR 文件,將字節碼與一組缺陷模式進行對比以發現可能的問題。Gradle使用如下的代碼為項目的構建腳本添加FindBugs的插件:

apply plugin: 'findbugs'

同樣也可以在FindBugs的配置階段(Configuration)設置其相關的屬性,比如Report的輸出目錄、檢查哪些sourceSet等。

3.3 JDepend

在開發Java項目時經常會遇到關於包混亂的問題, JDepend工具可以幫助你在開發過程中隨時跟蹤每個包的依賴性(引用/被引用),從而設計高維護性的架構,不論是在打包發布還是版本升級都會更加輕松。在構建腳本中加入如下代碼即可:

apply plugin: 'jdepend'

3.4 PMD

PMD是一種開源分析Java代碼錯誤的工具。與其他分析工具不同的是,PMD通過靜態分析獲知代碼錯誤,即在不運行Java程序的情況下報告錯誤。PMD附帶了許多可以直接使用的規則,利用這些規則可以找出Java源程序的許多問題。此外,用戶還可以自己定義規則,檢查Java代碼是否符合某些特定的編碼規范。在構建腳本中加入如下代碼:

apply plugin: 'pmd'

3.5 小結

上面提到的幾種代碼檢查插件apply到構建腳本之後,可以運行:

gradle check

來執行代碼質量檢查。更詳細的信息請查閱Gradle的官方文檔。運行結束後會在對應的項目目錄下的build文件夾下生成report。

對於Gradle沒有提供的代碼檢查工具,我們可以有兩種選擇:第一就是自己實現一個Gradle插件,第二就是調用Ant任務,讓Ant作為一個媒介去調用在Ant中已經有的代碼檢查工具,比如測試覆蓋率的Cobertura。我們的項目使用了Ant來調用Cobertura,但是為了使用方便,我們將它封裝為一個Gradle插件,這樣就可以在不同的項目裡重用。

4. 依賴

幾乎每個Java項目都會用到開源框架。同時,對於具有多個子模塊的項目來說,項目之間也會有所依賴。所以,管理項目中對開源框架和其他模塊的依賴是每個項目必須面對的問題。同時,Gradle也使用Repository來管理依賴。

4.1 Jar包依賴管理

Maven提出了使用Repository來管理Jar包,Ant也提供了使用Ivy來管理jar包。Gradle提供了對所有這些Respository的支持,可以從Gradle的官方文檔上了解更詳細的信息。

Gradle沿用Maven的依賴管理方法,通過groupId、name和version到配置的Repository裡尋找指定的Jar包。同樣,它也提供了和Maven一樣的構建生命周期,compile、runtime、testCompile和testRuntime分別對應項目不同階段的依賴。通過如下方式為構建腳本指定依賴:

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
    testCompile group:'junit', name: 'junit', version '4.11'
}

這裡分別指定group、name以及version,但是Gradle提供了一種更簡單的方式來指定依賴:

dependencies {
    compile 'org.hibernate:hibernate-core:3.6.7.Final'
    testCompile 'junit:junit:4.11'
}

這樣比Maven使用XML來管理依賴簡單多了,但是還可以更簡單一點。實際上這裡的compile和testCompile是Groovy為Gradle提供的方法,可以為其傳入多個參數,所以當compile有多個Jar包依賴的時候,可以同時指定到compile裡去,代碼如下:

compile(
	       'org.hibernate:hibernate-core:3.6.7.Final',
            'org.springframework:spring-context:3.1.4.RELEASE'
)

另外,當在Respository無法找到Jar包時(如數據庫的driver),就可以將這些Jar包放在項目的一個子目錄中,然後讓項目管理依賴。例如,我們可以在項目的根目錄下創建一個lib文件夾,用以存放這些Jar包。使用如下代碼可以將其添加到項目依賴中:

dependencies {
    compile(
	       'org.hibernate:hibernate-core:3.6.7.Final',
            'org.springframework:spring-context:3.1.4.RELEASE',
	       fileTree(dir: "${rootProject.projectDir}/lib", include: '*.jar')
)
}

4.2 子項目之間的依賴

對於多模塊的項目,項目中的某些模塊需要依賴於其他模塊,前面提到在初始化階段,Gradle為每個模塊都創建了一個Project對象,並且可以通過模塊的名字引用到該對象。在配置模塊之間的依賴時,使用這種方式可以告訴Gradle當前模塊依賴了哪些子模塊。例如,在我們的項目中,cis-war會依賴core子項目,就可以在cis-war的構建腳本中加上如下代碼:

dependencies {
    compile(
	       'org.hibernate:hibernate-core:3.6.7.Final',
             project(':core')
)
}

通過project(':core')來引用core子項目,在構建cis-war時,Gradle會把core加到ClassPath中。

4.3 構建腳本的依賴

除了項目需要依賴之外,構建腳本本身也可以有自己的依賴。當使用一個非Gradle官方提供的插件時,就需要在構建腳本裡指定其依賴,當然還需要指定該插件的Repository。在Gradle中,使用buildscript塊為構建腳本配置依賴。

比如在項目中使用cucumber-JVM作為項目BDD工具,而Gradle官方沒有提供它的插件,好在開源社區有人提供cucumber的插件。在構建腳本中添加如下代碼:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "gradle-cucumber-plugin:gradle-cucumber-plugin:0.2"
    }
}
apply plugin: com.excella.gradle.cucumber.CucumberPlugin

5. 其他

5.1 apply其他Gradle文件

當一個項目很復雜的時候,Gradle腳本也會很復雜,除了將子項目的配置移到對應項目的構建腳本之外,還可以可以按照不同的功能將復雜的構建腳本拆分成小的構建腳本,然後在build.gradle裡使用apply from,將這些小的構建腳本引入到整體的構建腳本中去。比如在一個項目中既使用了Jetty,又使用了Cargo插件啟動JBoss,就可以把他們分別提到jetty.gradle和jboss.gradle,然後在build.gradle裡使用如下的代碼將他們引入進來:

apply from: "jetty.gradle"
apply from: "jboss.gradle"

5.2 project的目錄

在腳本文件中,需要訪問項目中的各級目錄結構。Gradle為Project對象定義了一些屬性指向項目的根目錄,方便在腳本中引用。

rootDir:在子項目的腳本文件中可以通過該屬性訪問到根項目路徑。

rootProject:在子項目中,可以通過該屬性獲取父項目的Project對象。

5.3 使用Wrapper指定Gradle的版本

為了統一項目中Gradle的版本,可以在構建腳本中通過定義一個wrapper的Task,並在該Task中指定Gradle的版本以及存放Gradle的位置。

task wrapper(type: Wrapper) {
    gradleVersion = '1.0'
    archiveBase = 'PROJECT'
    archivePath = 'gradle/dists'
}

運行gradle wrapper, 就會在根項目目錄下創建一個wrapper的文件夾,會包含wrapper的Jar包和properties文件。之後就可以使用gradlew來運行task。第一次使用gradlew執行task的時候,會在項目根目錄下的gradle/dists下下載你指定的Gradle版本 。這樣在項目構建的時候,就會使用該目錄下的Gradle,保證整個團隊使用了相同的Gradle版本。

5.4 使用gradle.properties文件

Gradle構建腳本會自動找同級目錄下的gradle.properties文件,在這個文件中可以定義一些property,以供構建腳本使用。例如,我們要使用的Repository需要提供用戶名和密碼,就可以將其配置在gradle.properties中。這樣,每個團隊成員都可以修改該配置文件,卻不用上傳到代碼庫中對團隊其他成員造成影響。可以使用如下的代碼定義:

username=user
password=password

在構建腳本中使用"${username} "就可以訪問該文件中定義的相關值。

由於篇幅有限,本文只是我在一個大型Java項目上使用Gradle的部分經驗,並未涵蓋所有Gradle相關的知識,包括如何編寫Gradle插件以及Gradle對其他語言的構建,讀者可以通過閱讀Gradle的官方文檔(比起其他開源軟件,Gradle的另一特點就是文檔詳細)來了解。另外,Gradle是基於Groovy的構建工具,在使用Gradle的時候也需要了解和使用Groovy。所以,在學習Gradle插件的過程中,也能學會Groovy相關的用法,可謂一舉兩得。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved