在進行Java開發的過程中,我接觸到了Maven這套構建工具。所以,花費了點時間學習了一下這套構建工具,在學習過程中學習到的有關Maven的知識,在這裡分享給大家。
首先,在介紹Maven這套工具之前,我們得了解Maven是什麼。
Maven,在依地語中的意思是知識的積累,Maven在最初的時候,是作為Jakarta的Turbine項目的構建工具。在Maven出現之前,不同的Java項目使用不同的Ant配置進行構建,並且將jar包包含在版本控制系統(CVS)中,沒有一套統一的構建工具。如果有一套工具,可以擁有一套標准的方法來構建一個項目,並且可以清楚的定義一個項目是由哪些部分組成的,擁有一種簡單的方法發布項目的信息,在不同的項目之間可以分享jar包。出於這個目的,Maven被創造了出來。
Maven最初始的目標是讓開發者可以在最短的周期內可以快速的理解一個項目。為了達到這個目的,Maven解決了一下幾個問題:
在使用Maven之前,我們需要確保我們已經安裝了Maven構建工具。沒有安裝Maven構建工具的,可以參考官方提供的手冊參考如何安裝Maven
在安裝了Maven以後,可以通過命令 mvn -version
查看Maven的版本信息:
$ mvn -version
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T19:57:37+08:00)
Maven home: /usr/local/opt/maven
Java version: 1.7.0_79, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "mac os x", version: "10.10.2", arch: "x86_64", family: "mac"
接下來,我們通過Maven創建一個新的項目開始。
$ mvn -B archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DgroupId=com.myapp \
-DartifactId=myapp
在上面的Maven命令中,我們創建了一個名為myapp
的普通Java項目。一旦我們執行了上面的命令,就會在當前目錄下創建一個目錄為myapp
的工程。在這個工程目錄下,包含了一個名為pom.xml
的文件,這個新創建的pom文件內容大致如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myapp</groupId>
<artifactId>myapp</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>myapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
這個pom文件表示了當前這個項目的項目對象模型(Project Object Model(POM)
。在Maven中,POM是它進行操作的基本單位。Maven的本質是以圍繞POM這個概念為中心來管理整個項目的。POM中包含了項目中所有和項目相關的重要的信息,並且提供了類似一站式購物那樣的依賴管理方式,可以很方便的找到當前項目關聯的所有依賴來項目。
上面的pom.xml文件中的內容,包含了當前這個項目的相關信息。我們首先就上面這個POM文件中的一些元素,解釋下具體的含義:
project
這個元素是Maven的pom.xml文件的頂層元素。每個POM文件都是以一個project
元素包裹的。modelVersion
這個元素指定了當前這個pom.xml文件使用的項目對象模型(POM)的版本。groupId
這個元素表示創建這個項目的組織的唯一標識。這個元素的值是區分一個項目的關鍵信息之一,它的值通常是由該項目的組織的域名的反寫產生的(和Java的包名的機制一樣)。artifactId
這個元素是唯一標識了該項目最終生成的artifact(可以理解為是我們編寫代碼產生的一個程序,所以可以理解為是手工作品)。一個項目的artifact一般是一個jar
文件。一個項目最終生成的artifact的名字的格式是<artifactId>-<version>.<extension>
,比如上面的項目生成的artifact為myapp-1.0.jar
。packaging
這個元素指定了該artifact打包的類型(比如:jar、war、ear等)。這不只是意味著該artifact是以什麼方式打包,也指定了在構建過程中會用到的特定的生命周期(所謂的生命周期,簡單的說就是構建的過程)。packaging
元素的默認值是JAR
。version
這個元素指定了項目生成的artifact的版本號。在版本號中會包含當前項目的進度,比如這裡的SNAPSHOT
。name
這個元素表示項目的名字,常用於生成的文檔中。url
這個元素表示該項目所在的站點,常用於生成的文檔中。description
這個元素提供了對項目的描述,通常用於生成的文檔中。在項目被創建以後,除了會生成上面的pom.xml文件,還會產生一個標准的目錄結構:
myapp
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- myapp
| `-- App.java
`-- test
`-- java
`-- com
`-- myapp
`-- AppTest.java
上面的目錄結構是Maven項目的標准布局,項目的源代碼在目錄${basedir}/src/main/java
目錄下,而項目的測試代碼存放在目錄${basedir}/src/test/java
目錄下。對於${basedir},這裡表示的是包含了pom.xml文件的目錄,也就是項目的根目錄。
現在,我們已經簡單介紹了maven相關的概念和maven標准的目錄結構。但是,在我們使用Maven構建項目之前,我們先簡單了解下Maven的生命周期。
Maven的構建機制,是圍繞生命周期(lifecycle)這個概念進行構建的。這意味著構建和發布一個項目的整個過程是預先被定義了的。采用這種方式進行項目構建,可以讓用戶可以在學習很少的一部分命令的情況下通過POM對項目進行構建。
在Maven中,內建了三種構建生命周期:default
、clean
、site
。default
生命周期處理項目的部署,clean
生命周期處理項目構建後的清理工作,site
生命周期對項目的站點文檔進行生成。
Maven的生命周期,又是由不同的階段(phase)構成的。每一個生命周期,都包含了一系列的階段,每一個階段都表示了生命周期中的一個狀態。比如,對於default
生命周期來說,包含了如下的這些階段:
Maven在執行default
生命周期的時候,會順序執行這些階段來完成不同的工作。
現在我們已經安裝好Maven,並且對Maven的相關概念有了一些認識。下面,我們可以開始使用Maven對我們的項目進行構建了。
在前面,我們已經創建了一個名為myapp
的項目。現在,我們可以通過下面的命令對這個項目進行編譯。
$ mvn compile
這個命令執行以後,會有類似下方的輸出:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ myapp ---
...
[INFO] skip non existing resourceDirectory /Users/duke/practise/myapp/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ myapp ---
[INFO] Changes detected - recompiling the module!
...
[INFO] Compiling 1 source file to /Users/duke/practise/myapp/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.159 s
[INFO] Finished at: 2015-10-06T18:57:37+08:00
[INFO] Final Memory: 11M/156M
[INFO] ------------------------------------------------------------------------
在執行這個命令以後,Maven會首先去下載所有構建當前項目所需要的插件,以及所有被當前項目所依賴所有依賴項目。從上面的輸出中可以看出,我們最終構建後的文件被輸出到目錄${basedir}/target/classes
中,這個目錄是Maven約定的一個標准目錄。使用Maven的好處之一,就是當我們遵循Maven的約定以後,我們可以使用盡可能少的配置就可以讓Maven為我們構建項目。
現在,我們已經成功地編譯了我們的項目。接下來,我們可以讓Maven對單元測試進行編譯和執行,通過執行下面的命令,可以讓Maven編譯和執行我們寫的單元測試:
$ mvn test
上面的命令會有大致如下的輸出:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
...
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ myapp ---
[INFO] Nothing to compile - all classes are up to date
...
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ myapp ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/duke/practise/myapp/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ myapp ---
[INFO] Surefire report directory: /Users/duke/practise/myapp/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.myapp.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.004 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.799 s
[INFO] Finished at: 2015-10-06T19:08:08+08:00
[INFO] Final Memory: 13M/156M
[INFO] ------------------------------------------------------------------------
從輸出中我們可以看到,Maven在編譯和執行單元測試之前,會首先編譯main
中的項目代碼,然後才會對test
中的單元測試進行編譯和執行,並提供一個有關單元測試結果的簡單報告。
在這裡,我們使用surefire
插件對單元測試進行執行。surefire
插件會對符合該插件約定的命名規則的單元測試文件進行搜索,然後進行執行。默認會執行以下命名規則的文件:
默認會排除以下命名規則的文件
當然,如果只是需要對單元測試進行編譯而不需要執行,可以運行命令mvn test-comiple
實現。
現在,我們已經對項目進行編譯測試過了,我們接下來需要對項目進行打包。當前項目,我們在pom.xml中的packaging
元素中指定了打包的類型為jar
。所以我們可以通過下面的命令來打jar包:
$ mvn package
執行這個命令的輸出大致如下:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
...
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myapp ---
[INFO] Building jar: /Users/duke/practise/myapp/target/myapp-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.741 s
[INFO] Finished at: 2015-10-06T19:41:05+08:00
[INFO] Final Memory: 10M/156M
[INFO] ------------------------------------------------------------------------
Maven在執行這個命令的時候,會從pom.xml文件中獲得打包的類型,在這個項目中為jar包類型。然後將打出來的jar輸出到目錄${basedir}/target
下。
在打完包以後,我們的jar包現在還是留在我們的項目的target目錄下,為了將這個jar部署到我們的本地倉庫(默認是~/.m2/repository
)中以供別的項目使用,我們需要使用如下命令將當前項目的jar包部署到本地倉庫中:
$ mvn install
到目前為止,我們已經學習了怎麼對項目進行打包和部署到本地倉庫中了。
現在,我們如果需要對構建除的文件進行清理,我們需要使用如下的命令:
$ mvn clean
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ myapp ---
[INFO] Deleting /Users/duke/practise/myapp/target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.255 s
[INFO] Finished at: 2015-10-06T19:47:25+08:00
[INFO] Final Memory: 6M/123M
[INFO] ------------------------------------------------------------------------
這個命令會刪除target
目錄,因為在這個目錄下包含了我們構建這個項目後輸出的所有文件。現在,我們的項目就回到被構建之前了。
我們如果使用IDE開發環境,我們可以使用Maven生成當前項目相關的IDE的描述文件。
對於IntelliJ IEDA環境,可以用如下命令進行生成:
$ mvn idea:idea
對於eclipse環境,可以用如下的命令生成:
$ mvn eclipse:eclipse
http://maven.apache.org/guides/getting-started/index.html