使用Gradle構建Java專案

位元組技術發表於2015-05-07

使用Gradle構建Java專案

這個手冊將通過一個簡單的Java專案向大家介紹如何使用Gradle構建Java專案。

我們將要做什麼?

我們將在這篇文件航中建立一個簡單的Java專案,然後使用Gradle構建它。

需要準備什麼?

  • 預留15分鐘空閒時間
  • 一件稱手的兵器(你最喜歡的IDE或者文字編輯器
  • Java環境([JDK6](http://www.oracle.com/technetwork/java/javase/downloads/index.html”JDK”及以上版本)

如何完成這個手冊的內容?

與大多數Spring的入門手冊一樣,你可以從頭開始一步步完成教程中的每一步工作,也可以跳過你已經爛熟的基礎步驟。不管採用那種方式,你最後都會得到可工作的程式碼。

  1. 如果要重頭開始,猛戳這裡
  2. 如果要跳過基礎部分,需執行以下操作:
    • 下載並解壓本文件相關原始碼,或者使用Git克隆一個:git clone https://github.com/spring-guides/gs-gradle.git
    • cd 進入 gs-gradle/initial
    • 參考到安裝Gradle部分

當你完成後,你可以使用gs-gradle/complete來檢查你的結果。

配置專案

首先需要配置一個專案給Gradle進行構建。為了保證我們能專注於Gradle,目前最好建立最簡單的Java專案。

建立目錄結構

在專案主目錄下,建立以下子目錄;在*nix系統下可以使用命令:mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

src/main/java/hello目錄中,你可以建立任何Java類。為簡單起見並且為了與指南的其餘部分保持一致,我們建議建立兩個雷HelloWorld.javaGreeter.java

src/main/java/hello/HelloWorld.java的原始碼:

package hello;

public class HelloWorld {
  public static void main(String[] args) {
    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}

src/main/java/hello/Greeter.java的原始碼:

package hello;

public class Greeter {
  public String sayHello() {
    return "Hello world!";
  }
}

安裝Gradle

到目前為止,我們已經搭建了一個可以用來使用Gradle構建的專案,現在到了安裝Gradle的時候了。

Gradle可以從http://www.gradle.org/downloads下載。我們僅需要下載Gradle的二進位制釋出包,所以在剛才提供的連線上尋找gradle-version-bin.zip檔案(當然,也可以下載gradle-version-all.zip,它包含原始碼、文件以已編譯程式碼)

解壓縮下載的檔案,並將解壓後目錄中的bin目錄加到環境變數中。

可以在命令列中執行以下程式碼來測試Gradle是否安裝成功

gradle

如果你很幸運,嘛事都OK,你會看到下面的welcome資訊:

:help

Welcome to Gradle 1.8.

To run a build, run gradle <task> ...

To see a list of available tasks, run gradle tasks

To see a list of command-line options, run gradle --help

BUILD SUCCESSFUL

Total time: 2.675 secs

看到這個了,說明Gradle已經成功安裝到系統中了。如果沒看到……再去看看Gradle的手冊先。

Gradle可以做些什麼呢?

Gradle已經安裝到系統上了,那麼它可以做什麼呢?在我們為專案建立build.gradle檔案之前,我們可以先問一下Gradle目前有哪些可用的任務(Tasks):

gradle tasks

我們可以看到可用任務(Tasks)的列表。假設你執行Gradle的目錄不存在build.gradle檔案,你可以看到一些非常基礎的任務,類似於:

:tasks

== All tasks runnable from root project

== Build Setup tasks
setupBuild - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]

== Help tasks
dependencies - Displays all dependencies declared in root project 'gs-gradle'.
dependencyInsight - Displays the insight into a specific dependency in root project 'gs-gradle'.
help - Displays a help message
projects - Displays the sub-projects of root project 'gs-gradle'.
properties - Displays the properties of root project 'gs-gradle'.
tasks - Displays the tasks runnable from root project 'gs-gradle'.

To see all tasks and more detail, run with --all.

BUILD SUCCESSFUL

Total time: 3.077 secs

儘管上面的列出的任務是可用的,但是如果沒有專案的構建配置他們無法提供太多的價值。當配置了專案的build.gradle後,一些任務將變得非常有用。

如果在build.gradle中配置了外掛(plugins)上面的任務列表會變得更長,最好在配置外掛後使用gradle task看看那些任務是可用的。

剛說到配置外掛,馬上我們就會配置一個外掛來啟用基礎的Java構建功能。

構建Java程式碼

先從簡單的開始,建立一個最簡單的只有一行的build.gradle檔案:

apply plugin: 'java'

別看只有一行配置,提供的能力可不是一點點哦。再執行一下gradle task,我們可以看到任務列表中增加了一些內容,比如:用來編譯java專案的任務、用來建立JavaDoc的任務、用來執行單元測試的任務。

我們經常使用的任務是gradle build,這個任務執行以下操作:編譯、執行單元測試、組裝Jar檔案:

gradle build

幾秒鐘以後,會看到”BUILD SUCCESSFUL”輸出,說明構建已經完成了。

可以到”build”目錄中檢視構建結構,在這個目錄中我們可以看到很多子目錄,其中有三個我們需要特別注意:

  • classes: 儲存被編譯後的.class檔案
  • reports: 構建報告(如:測試報告)
  • lib: 組裝好的專案包(通常為:.jar或者.war檔案)

classes目錄包含編譯生成的所有.class檔案。執行完編譯後,我們應該可以在這裡找到”HelloWorld.class”和”Greeter.class”。

到目前為止,我們專案並沒有申明任何依賴,所以”debendency_cache”目錄是空的。

“reports”目錄會包含專案單元測試的測試報告,當然,當前專案並未編寫任何單元測試,所以,也是空目錄。

“lib”目錄包含打包後的jar或war檔案,在後面的內容中我們將學會如何定義JAR的名稱和版本號。

申明依賴

我們的Hello World例程非常簡單且不依賴於任何第三方庫,但是大多數應用程式都會依賴第三方庫提供的通用或複雜的功能。

例如:假設我們希望更好的說”Hello World!”,我們希望應用程式能同時輸出當前的日期和時間。當然這可以使用Java自身的日期和時間相關庫,但是我們可以使用”Joda Time”庫實現更有趣的功能。

首先,把HelloWorld.jara類修改成下面這樣:

package hello;

import org.joda.time.LocalTime;

public class HelloWorld {
  public static void main(String[] args) {
    LocalTime currentTime = new LocalTime();
    System.out.println("The current local time is: " + currentTime);

    Greeter greeter = new Greeter();
    System.out.println(greeter.sayHello());
  }
}

這裡我們的HelloWorld使用”Joda Time”的LocalTime類來獲取和輸出當前時間。

如果我們馬上執行gradle build來構建專案,構建過程將會失敗,因為我們並未將”Joda Time”庫宣告為編譯時依賴庫。

首先,我們需要新增一些配置來定義第三方庫的來源:

repositories {
    mavenLocal()
    mavenCentral()
}

上面的repositories定義,告訴構建系統通過Maven中央庫來檢索專案依賴的軟體包,Gradle在很大程度上依賴Maven構建工具的許多約定和基礎功能,包括使用Maven中央的庫來處理依賴關係。

現在我們可以使用第三方庫了,但現需要定義:

dependencies {
    compile "joda-time:joda-time:2.2"
}

使用dependencies塊,我們定義了一條Joda Time的依賴項。這裡,明確指定使用joda-time組內的版本為2.2的joda-time庫。

另一個要注意的是,我們在這個依賴定義中指定依賴是compile範圍的。意思是,這個庫在編譯和執行時都需要(如果我們正在構建WAR檔案,這個檔案會在/WEB-INF/libs目錄下)。另外值得注意的依賴型別包括:

  • providedCompile:在編譯期間需要這個依賴包,但在執行期間可能由容器提供相關元件(比如:Java Servlet API)
  • testCompile:依賴項僅在構建和執行測試程式碼時需要,在專案執行時不需要這個依賴項。

最後,我們來定義我們將生成的Jar檔案的名字:

jar {
    baseName = 'gs-gradle'
    version =  '0.1.0'
}

jar塊定義如何命名JAR檔案,在上面的例子中,我們的JAR檔案的名字為:gs-gradle-0.1.0.jar

注:這個時候如果執行gradle build,Gradle會花一些時間從Maven中央庫下載Joda Time包(具體下載時間依賴於你的網速)

使用Gradle Wrapper來構建專案

Gradle Wrapper是開始一個Gradle構建的首選方式。它包含了windows批處理以及OS X和Linux的Shell指令碼。這些指令碼允許我們在沒有安裝Gradle的系統上執行Gradle構建。要實現這個功能,我們需要在我們的build.gradle檔案中增加以下程式碼:

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

執行下面程式碼來下載和初始化wrapper指令碼:

gradle wrapper

命令執行完後,我們可以看到增加了一些新檔案。有兩個檔案在根目錄下,wapper的jar檔案和properties檔案在新增的gradle/wrapper目錄下。

└── initial
    └── gradlew
    └── gradlew.bat
    └── gradle
        └── wrapper
            └── gradle-wrapper.jar
            └── gradle-wrapper.properties

現在Gradle Wrapper已經可以用來構建系統了。把這些檔案增加到版本控制系統中,然後再任何時候、任何地方只要遷出這些檔案就一個按照同樣的方式(與當前生成 Wrapper的Gradle版本一致)構建系統。執行wrapper指令碼來構建系統,跟我們之前橋的命令很像:

./gradlew build

當第一次通過wrapper使用指定版本的Gradle構建系統時,wrapper首先下載對應版本的Gradle可執行檔案。Gradle Wrapper的所有檔案在都可以被提交到版本庫中,所以,任何人都可以在沒有安裝Gradle的環境下使用相同版本的Gradle構建系統。

在這個時候,我們需要重新構建我們的程式碼,構建的結果目錄如下:

build
├── classes
│   └── main
│       └── hello
│           ├── Greeter.class
│           └── HelloWorld.class
├── dependency-cache
├── libs
│   └── gs-gradle-0.1.0.jar
└── tmp
    └── jar
        └── MANIFEST.MF

Jar檔案中包含我們希望打包的GretterHelloWorld類。

$ jar tvf build/libs/gs-gradle-0.1.0.jar
  0 Fri May 30 16:02:32 CDT 2014 META-INF/
 25 Fri May 30 16:02:32 CDT 2014 META-INF/MANIFEST.MF
  0 Fri May 30 16:02:32 CDT 2014 hello/
369 Fri May 30 16:02:32 CDT 2014 hello/Greeter.class
988 Fri May 30 16:02:32 CDT 2014 hello/HelloWorld.class

需要注意的,即使我們宣告瞭joda-time依賴,但這裡也沒有包括對應的庫檔案,而且生成的JAR檔案也不是可執行JAR檔案。

要想讓程式碼可以執行,我們可以使用Gradle的application外掛。增加以下內容到build.gradle檔案中。

apply plugin: 'application'

mainClassName = 'hello.HelloWorld'

現在我們的app可以執行了。

$ ./gradlew run
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:run
The current local time is: 16:16:20.544
Hello world!

BUILD SUCCESSFUL

Total time: 3.798 secs

為了能夠將依賴包也以一起打包,比如,我們希望構建一個WAR包,可以包含第三方元件的打包格式,我們可以使用Gradle的WAR外掛。如果我們使用Spring Boot並且希望得到一個可執行的JAR檔案,我們可以使用spring-boot-gradle-plugin外掛。在我們的示例中,gradle沒有足夠的資訊來了解我們的目標系統。但是,目前介紹的內容已經足夠我們開始使用Gradle了。

下面是本文需要用的的build.gradle檔案:

apply plugin: 'java'
apply plugin: 'Eclipse'
apply plugin: 'application'

mainClassName = 'hello.HelloWorld'

// tag::repositories[]
repositories {
    mavenLocal()
    mavenCentral()
}
// end::repositories[]

// tag::jar[]
jar {
    baseName = 'gs-gradle'
    version =  '0.1.0'
}
// end::jar[]

// tag::dependencies[]
dependencies {
    compile "joda-time:joda-time:2.2"
}
// end::dependencies[]

// tag::wrapper[]
task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}
// end::wrapper[]

注意:檔案中有很多start/end註釋,這些註釋是為了方便拷貝檔案中的內容到文章的各個部分,在實際使用中不需要包含他們。

總結

恭喜,你已經建立了一個簡單的然而可用的Gradle構建檔案來構建Java專案。

相關文章