1. 程式人生 > >maven(四)maven使用入門

maven(四)maven使用入門

1、編寫pom

Maven 專案的核心是 pom.xml。POM(Project Object Model,專案物件模型) 定義了專案的基本資訊, 用於描述專案如何構建, 宣告專案依賴, 等等。 現在我們先為 Hello World專案編寫一個最簡單的 pom.xml。
首先建立一個名為 mavenTests 的資料夾 , 開啟該資料夾,新建一個名為 pom.xml 的檔案

這裡寫圖片描述

根元素下的第一個子元素 modelVersion 指定了當前 POM 模型的版本,對於 Maven2 及 Maven 3 來說,它只能是 4.0.0。
這段程式碼中最重要的是 groupId, artifactId 和 version 三行。 這三個元素定義了一個專案基本的座標, 在 Maven的世界,任何的 jar、pom 或者 war 都是以基於這些基本的座標進行區分的。groupId 定義了專案屬於哪個組,這個組往往和專案所在的組織或公司存在關聯,譬如你在 googlecode 上建立了一個名為 myapp 的專案,那麼 groupId 就應該是 com.googlecode.myapp,如果你的公司是 mycom,有一個專案為 myapp,那麼 groupId 就應該是 com.mycom.myapp。

artifactId 定義了當前 Maven 專案在組中唯一的 ID, 我們為這個 Hello World 專案定義 artifactId 為 maven。為不同的子專案(模組)分配 artifactId,如:maven-util、maven-domain、maven-web 等等。顧名思義,version 指定了 mavenTests 專案當前的版本——0.0.1-SNAPSHOT。SNAPSHOT 意為快照,說明該專案還處於開發中,是不穩定的版本。隨著專案的發展,version 會不斷更新,如升級為 1.0、1.1-SNAPSHOT、1.1、2.0 等等。最後有一個name元素聲明瞭一個對於使用者更為友好的專案名稱, 這不是必須的。

沒有任何實際的 Java 程式碼,我們就能夠定義一個 Maven 專案的 POM,這體現了 Maven 的一大優點,它能讓專案物件模型最大程度地與實際程式碼相獨立,我們可以稱之為解耦,或者正交性,這在很大程度上避免了 Java程式碼和 POM 程式碼的相互影響。比如當專案需要升級版本時,只需要修改 POM,而不需要更改 Java 程式碼;而在POM 穩定之後,日常的 Java 程式碼開發工作基本不涉及 POM 的修改。

2.編寫主程式碼

專案主程式碼和測試程式碼不同,專案的主程式碼會被打包到最終的構件中(比如 jar) ,而測試程式碼只在執行測試時用到,不會被打包。預設情況下,Maven 假設專案主程式碼位於 src/main/java 目錄,我們遵循 Maven 的約定,建立該目錄,然後在該目錄下建立檔案 com.alex.maven

這裡寫圖片描述

這是一個簡單的 Java 類,它有一個 sayHello()方法,一個String引數,返回一個 String。同時這個類還帶有一個 main 方法,建立一個 HelloWorld 例項,呼叫 sayHello()方法,傳一個Maven字串,並將結果輸出到控制檯。關於該 Java 程式碼有兩點需要注意。首先,在 95%以上的情況下,我們應該把專案主程式碼放到 src/main/java/目錄下(遵循 Maven 的約定) ,而無須額外的配置,Maven 會自動搜尋該目錄找到專案主程式碼。其次,該 Java 類的包名是 package com.alex.maven.Helloworld,這與我們之前在 POM 中定義的 groupId 和 artifactId 相吻合。一般來說,專案中 Java 類的包都應該基於專案的 groupId 和 artifactId,這樣更加清晰,更加符合邏輯,也方便搜尋構件或者 Java 類。程式碼編寫完畢後,我們使用 Maven 進行編譯,在專案根目錄下執行命令 mvn clean compile ,我們會得到如下輸出:

這裡寫圖片描述

clean 告訴 Maven 清理輸出目錄 target/,compile 告訴 Maven 編譯專案主程式碼,從輸出中我們看到 Maven 首先執行了 clean:clean 任務,刪除 target/目錄,預設情況下 Maven 構建的所有輸出都在 target/目錄中;接著執行resources:resources 任務(未定義專案資源,暫且略過) ;最後執行 compiler:compile 任務,將專案主程式碼編譯至target/classes 目錄。

3、編寫測試程式碼

為了使專案結構保持清晰,主程式碼與測試程式碼應該分別位於獨立的目錄中。3.2 節講過 Maven 專案中預設的主程式碼目錄是 src/main/java,對應地,Maven 專案中預設的測試程式碼目錄是 src/test/java。因此,在編寫測試用例之前,我們先建立該目錄。

在 Java 世界中,由 Kent Beck 和 Erich Gamma 建立的 JUnit 是事實上的單元測試標準。要使用 JUnit,我們首先需要為 Hello World 專案新增一個 JUnit 依賴,修改專案的 POM 為 Hello World 的 POM 新增依賴

這裡寫圖片描述

程式碼中添加了 dependencies 元素,該元素下可以包含多個 dependency 元素以宣告專案的依賴,這裡我們添加了一個依賴——groupId 是 junit,artifactId 是 junit,version 是 4.0。前面我們提到 groupId、 artifactId 和 version 是任何一個 Maven 專案最基本的座標, JUnit 也不例外,有了這段宣告,Maven 就能夠自動下載 junit-4.0.jar。也許你會問,Maven 從哪裡下載這個 jar呢?在 Maven 之前,我們可以去 JUnit 的官網下載分發包。而現在有了 Maven,它會自動訪問中央倉庫( http://repo1.maven.org/maven2/ ),下載需要的檔案。讀者也可以自己訪問該倉庫,開啟路徑junit/junit/4.0/,就能看到 junit-4.0pom 和 junit-4.0.jar
上述 POM 程式碼中還有一個值為 test 的元素 scope,scope 為依賴範圍,若依賴範圍為 test 則表示該依賴只對測試有效,換句話說,測試程式碼中的 import JUnit 程式碼是沒有問題的,但是如果我們在主程式碼中用 import JUnit程式碼,就會造成編譯錯誤。如果不宣告依賴範圍,那麼預設值就是 compile,表示該依賴對主程式碼和測試程式碼都有效。
配置了測試依賴, 接著就可以編寫測試類, 回顧一下前面的 HelloWorld 類, 現在我們要測試該類的 sayHello()方法,檢查其返回值是否為“Hello Maven”。在 src/test/java 目錄下建立檔案,
Hello World 的測試程式碼

這裡寫圖片描述

一個典型的單元測試包含三個步驟:一,準備測試類及資料;二,執行要測試的行為;三,檢查結果。上述樣例中,我們首先初始化了一個要測試的 HelloWorld 例項,接著執行該例項的 sayHello()方法並儲存結果到 result變數中,最後使用 JUnit 框架的 Assert 類檢查結果是否為我們期望的”Hello Maven”。在 JUnit 3 中,約定所有需要執行測試的方法都以 test 開頭,這裡我們使用了 JUnit 4,但我們仍然遵循這一約定,在 JUnit 4 中,需要執行的測試方法都應該以@Test 進行標註。

測試用例編寫完畢之後就可以呼叫 Maven 執行測試,執行 mvn clean test :

這裡寫圖片描述

我們看到 compiler:testCompile 任務執行成功了,測試程式碼通過編譯之後在 target/test-classes 下生成了二進位制檔案,緊接著 surefire:test 任務執行測試,surefire 是 Maven 世界中負責執行測試的外掛,這裡它執行測試用例HelloWorldTest,並且輸出測試報告,顯示一共運行了多少測試,失敗了多少,出錯了多少,跳過了多少。顯然,我們的測試通過了——BUILD SUCCESSFUL。

4、打包和執行

將專案進行編譯、測試之後,下一個重要步驟就是打包(package) 。Hello World 的 POM 中沒有指定打包型別,使用預設打包型別 jar,我們可以簡單地執行命令 mvn clean package 進行打包,可以看到如下輸出:

這裡寫圖片描述

類似地,Maven 會在打包之前執行編譯、測試等操作。這裡我們看到 jar:jar 任務負責打包,實際上就是 jar外掛的 jar 目標將專案主程式碼打包成一個名為maven-0.0.1-SNAPSHOT.jar 的檔案,該檔案也位於 target/輸出目錄中,它是根據 artifact-version.jar 規則進行命名的,如有需要,我們還可以使用 finalName 來自定義該檔案的名稱。
至此,我們得到了專案的輸出,如果有需要的話,就可以複製這個 jar 檔案到其他專案的 Classpath 中從而使用 HelloWorld 類。但是,如何才能讓其他的 Maven 專案直接引用這個 jar 呢?我們還需要一個安裝的步驟,執行mvn clean install:

這裡寫圖片描述

在打包之後,我們又執行了安裝任務 install:install,從輸出我們看到該任務將專案輸出的 jar 安裝到了 Maven本地倉庫中,我們可以開啟相應的資料夾看到 maven 專案的 pom 和 jar。之前講述 JUnit 的 POM 及 jar 的下載的時候, 我們說只有構件被下載到本地倉庫後, 才能由所有 Maven 專案使用, 這裡是同樣的道理, 只有將 HelloWorld 的構件安裝到本地倉庫之後,其他 Maven 專案才能使用它。
我們已經將體驗了 Maven 最主要的命令: mvn clean compile、 、 mvn clean test、 、 mvn clean package、 、 mvn cleaninstall。執行 test 之前是會先執行 compile 的,執行 package 之前是會先執行 test 的,而類似地,install 之前會執行 package。我們可以在任何一個 Maven 專案中執行這些命令,而且我們已經清楚它們是用來做什麼的。
到目前為止,我們還沒有執行 maven 專案,不要忘了 HelloWorld 類可是有一個 main 方法的。預設打包生成的 jar 是不能夠直接執行的,因為帶有 main 方法的類資訊不會新增到 manifest 中(我們可以開啟 jar 檔案中的META-INF/MANIFEST.MF 檔案,將無法看到 Main-Class 一行)。為了生成可執行的 jar 檔案,我們需要藉助maven-shade-plugin,配置該外掛如下:

這裡寫圖片描述

plugin 元素在 POM 中的相對位置應該在<project><build><plugins>下面。我們配置了 mainClass 為com.alex.maven.HelloWorld,專案在打包時會將該資訊放到 MANIFEST 中。現在執行 mvn clean
install , 待 構 建 完 成 之 後 打 開 target/ 目 錄 , 我 們 可 以 看 到 maven-0.0.1-SNAPSHOT.jar 和
original-maven-0.0.1-SNAPSHOT.jar,前者是帶有 Main-Class 資訊的可執行 jar,後者是原始的 jar,

現在,我們在專案根目錄中執行該 jar 檔案:
E:\test-maven\mavenTests\target>java -jar maven-0.0.1-SNAPSHOT.jar

Hello Maven

控制檯輸出為 Hello Maven,這正是我們所期望的。
這裡介紹了 maven 專案,側重點是 Maven 而非 Java 程式碼本身,介紹了 POM、Maven 專案結構、以及如何編譯、測試、打包,等等。

5、使用 Archetype 生成專案骨架

maven 專案中有一些 Maven 的約定:在專案的根目錄中放置 pom.xml,在 src/main/java 目錄中放置專案的主程式碼,在 src/test/java 中放置專案的測試程式碼。我之所以一步一步地展示這些步驟,是為了能讓可能是 Maven初學者的你得到最實際的感受。我們稱這些基本的目錄結構和 pom.xml 檔案內容稱為專案的骨架,當你第一次建立專案骨架的時候,你還會饒有興趣地去體會這些預設約定背後的思想,第二次,第三次,你也許還會滿意自己的熟練程度,但第四、第五次做同樣的事情,就會讓程式設計師惱火了,為此 Maven 提供了 Archetype 以幫助我們快速勾勒出專案骨架。

我們使用 maven archetype 來建立該專案的骨架,離開當前的 Maven 專案目錄。
如果是 Maven 3,簡單的執行:mvn archetype:generate
如果是 Maven 2,最好執行如下命令:mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-5:generate

我們實際上是在執行外掛 maven-archetype-plugin ,注意冒號的分隔 , 其格式為groupId:artifactId:version:goal , org.apache.maven.plugins 是 maven 官方外掛的 groupId, maven-archetype-plugin 是archetype 外掛的 artifactId,generate 是我們要使用的外掛目標。

緊接著我們會看到一段長長的輸出,有很多可用的 archetype 供我們選擇,包括著名的 Appfuse 專案的
archetype,JPA 專案的 archetype 等等。每一個 archetype 前面都會對應有一個編號,同時命令列會提示一個預設的編號,其對應的 archetype 為 maven-archetype-quickstart,我們直接回車以選擇該 archetype,緊接著 Maven 會提示我們輸入要建立專案的 groupId、artifactId、 version、以及包名 package,如下輸入並確認:

這裡寫圖片描述

Archetype 外掛將根據我們提供的資訊建立專案骨架。在當前目錄下,Archetype 外掛會建立一個名為
helloworld(我們定義的 artifactId)的子目錄,從中可以看到專案的基本結構:基本的 pom.xml 已經被建立,裡面包含了必要的資訊以及一個 junit 依賴;主程式碼目錄 src/main/java 已經被建立,在該目錄下還有一個 Java 類com.alex.maven.App, 注意這裡使用到了我們剛才定義的包名, 而這個類也僅僅只有一個簡單的輸出 Hello World!的 main 方法;測試程式碼目錄 src/test/java 也被建立好了,並且包含了一個測試用例com.alex.maven.AppTest。
Archetype 可以幫助我們迅速地構建起專案的骨架,在前面的例子中,我們完全可以在 Archetype 生成的骨架的基礎上開發 Hello World 專案以節省我們大量時間。此外,我們這裡僅僅是看到了一個最簡單的 archetype,如果你有很多專案擁有類似的自定義專案結構以及配置檔案,你完全可以一勞永逸地開發自己的 archetype,然後在這些專案中使用自定義的 archetype 來快速生成專案骨架。