Maven 項目構建基礎從屬於筆者的現代 Java 開發基礎系列文章,介紹了 Maven 的歷史背景與多種構建工具對比,以及 Maven 的基本配置安裝與使用;本文涉及的參考資料聲明在 Java 學習與實踐資料索引以及 Maven 學習與資料索引。本文整理時間也較早,最近由於整理 Java 相關的資料因此從新概括了下。html
Maven 是功能強大的構建工具可以幫咱們自動化構建過程,從清理、編譯、測試到生成報告,再到打包和部署。咱們只須要輸入簡單的命令(如 mvn clean install
),Maven 就會幫咱們處理繁瑣的任務;它最大化的消除了構建的重複,抽象了構建生命週期,而且爲絕大部分的構建任務提供了已實現的插件。好比說測試,咱們只須要遵循 Maven 的約定編寫好測試用例,當咱們運行構建的時候,這些測試便會自動運行。除此以外,Maven 能幫助咱們標準化構建過程。在 Maven 以前,十個項目可能有十種構建方式,但經過 Maven,全部項目的構建命令都是簡單一致的。有利於促進項目團隊的標準化。java
Maven 是筆者接觸的第一個脫離於 IDE 的命令行構建工具,筆者以前一直是基於 Visual Studio 下進行 Windows 驅動開發,並非很能明白 Builder 與 IDE 之間的區別。依賴大量的手工操做。編譯、測試、代碼生成等工做都是相互獨立的,很難一鍵完成全部工做。手工勞動每每意味着低效,意味着容易出錯。很難在項目中統一全部的 IDE 配置,每一個人都有本身的喜愛。也正是因爲這個緣由,一個在機器 A 上能夠成功運行的任務,到了機器 B 的 IDE 中可能就會失敗。git
在 Linux C 開發中咱們經常使用 Make 進行構建,不過 Make 將本身和操做系統綁定在一塊兒了;也就是說,使用Make,就不能實現(至少很難)跨平臺的構建,這對於Java來講是很是不友好的。此外,Makefile 的語法也成問題,不少人抱怨 Make 構建失敗的緣由每每是一個難以發現的空格或 Tab 使用錯誤。而在 Java 發展過程當中常見的自動化構建工具以 Ant、Maven、Gradle 爲表明,整個自動化流程每每包含如下步驟:編譯源代碼、運行單元測試和集成測試、執行靜態代碼分析、生成分析報告、建立發佈版本、部署到目標環境、部署傳遞過程以及執行冒煙測試和自動功能測試。github
和 Make 同樣,Ant 也都是過程式的,開發者顯式地指定每個目標,以及完成該目標所須要執行的任務。針對每個項目,開發者都須要從新編寫這一過程,這裏其實隱含着很大的重複。Maven 是聲明式的,項目構建過程和過程各個階段所需的工做都由插件實現,而且大部分插件都是現成的,開發者只須要聲明項目的基本元素,Maven 就執行內置的、完整的構建過程。這在很大程度上消除了重複。web
此外,Ant 是沒有依賴管理的,因此很長一段時間 Ant 用戶都不得不手工管理依賴,這是一個使人頭疼的問題。幸運的是,Ant 用戶如今能夠藉助 Ivy 管理依賴。而對於 Maven 用戶來講,依賴管理是理所固然的,Maven 不只內置了依賴管理,更有一個可能擁有全世界最多 Java 開源軟件包的中央倉庫,Maven 用戶無須進行任何配置就能夠直接享用。算法
而 Gradle 拋棄了 Maven 的基於 XML 的繁瑣配置;衆所周知 XML 的閱讀體驗比較差,對於機器來講雖然容易識別,但畢竟是由人去維護的。取而代之的是 Gradle 採用了領域特定語言 Groovy 的配置,大大簡化了構建代碼的行數。Maven 的設計核心 Convention Over Configuration 被 Gradle 更加發揚光大,而 Gradle 的配置即代碼又超越了Maven。在 Gradle 中任何配置均可以做爲代碼被執行的,咱們也能夠隨時使用已有的 Ant 腳本(Ant task 是 Gradle 中的一等公民)、Java 類庫、Groovy 類庫來輔助完成構建任務的編寫。在現代 Java 開發基礎系列文章中也有專門的章節講解 Gradle,筆者在 Android 與 Spring 項目構建中也會優先選擇 Gradle。spring
Maven 的安裝也很是方便,可從 Apache 官方下載最新的 Maven 壓縮包而後解壓,也可使用 SDK Man 執行安裝;若是是手動配置的話咱們還須要配置設置下系統的環境變量:apache
在用戶目錄下,咱們能夠發現 .m2 文件夾。默認狀況下,該文件夾下放置了 Maven 本地倉庫 .m2/repository。全部的 Maven 構件(artifact)都被存儲到該倉庫中,以方便重用。默認狀況下,~/.m2 目錄下除了 repository 倉庫以外就沒有其餘目錄和文件了,不過大多數 Maven 用戶須要複製 M2HOME/conf/settings.xml 文件到 ~/.m2/settings.xml。windows
部分經常使用的Maven命令以下:服務器
mvn -v # 查看maven版本 mvn compile # 編譯 mvn test # 測試 mvn package # 打包 mvn clean # 刪除 target mvn install # 安裝jar包到本地倉庫中 mvn archetype:generate -DgroupId=co.hoteam -DartifactId=Zigbee -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false # 建立一個新工程
衆所周知的緣由,國內有時候並不可以很順暢的訪問 Maven 的中央倉庫,每每咱們須要訪問國內的鏡像地址:
<mirror> <id>CN</id> <name>OSChina Central</name> <url>http://maven.oschina.net/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
或者編輯 ~/.m2/settings.xml 文件(若是沒有該文件,則複製 $M2HOME/conf/settings.xml),添加代理配置以下:
<settings> ... <pqroxies> <proxy> <id>my-proxy</id> <active>true</active> <protocol>http</protocol> <host>代理服務器主機名</host> <port>端口號</port> <!-- <username>***</username> <password>***</password> <nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts> --> </proxy> </proxies> ... </settings>
若是不行試試重啓機器或者eclipse等ide還不行試試下面這種方式:windows-->preferences-->maven-->installations add
這樣配置後將使用指定目錄下的maven,而非eclipse的maven內置插件。
(1)有時候執行mvn compile
時候會爆出沒法找到junit的錯誤,可能的解決方法有:
在pom.xml中引入junit依賴項,而且保證其scope爲compile:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
(2)有時候在Eclipse下執行mvn compile
或者相關命令時,會報某某文件出現不識別字符或者非UTF-8編碼,此時能夠作幾步檢查:
就像 Make 的 Makefile,Ant 的 build.xml 同樣,Maven 項目的核心是 pom.xml。首先建立一個名爲 hello-world 的文件夾,打開該文件夾,新建一個名爲 pom.xml 的文件,輸入其內容以下:
<?xml version="1.0" encoding="UTF-8"?> <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.wx.mvn</groupId> <artifactId>hello-world</artifactId> <version>1.0-SNAPSHOT</version> <name>Maven Hello World Project</name> </project>
在 pom.xml 定義 properties 標籤
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>1.2.6</spring.version> <developer.organization><![CDATA[xy公司]]></developer.organization> </properties>
以上內容就改爲了
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency>
也可使用 maven-properties 插件來支持外部變量
項目主代碼和測試代碼不一樣,項目的主代碼會被打包到最終的構件中(好比 jar),而測試代碼只在運行測試時用到,不會被打包。默認狀況下,Maven 假設項目主代碼位於 src/main/java
目錄,咱們遵循 Maven 的約定,建立該目錄,而後在該目錄下建立文件 com/wx/mvn/helloworld/HelloWorld.java
,其內容以下:
package com.wx.mvn.helloworld; public class HelloWorld { public String sayHello() { return "Hello Maven"; } public static void main(String[] args) { System.out.print( new HelloWorld().sayHello() ); } }
關於該 Java 代碼有兩點須要注意。首先,大部分狀況下咱們應該把項目主代碼放到 src/main/java/ 目錄下(遵循Maven的約定),而無須額外的配置,Maven 會自動搜尋該目錄找到項目主代碼。其次,該 Java 類的包名是 com.wx.mvn.helloworld,這與咱們以前在 POM 中定義的 groupId 和 artifactId 相吻合。通常來講,項目中 Java 類的包都應該基於項目的 groupId 和 artifactId,這樣更加清晰,更加符合邏輯,也方便搜索構件或者 Java 類。 代碼編寫完畢後,咱們使用 Maven 進行編譯,在項目根目錄下運行命令 mvn clean compile
便可。Maven 首先執行了clean:clean 任務,刪除 target/ 目錄,默認狀況下 Maven 構建的全部輸出都在 target/ 目錄中;接着執行 resources:resources 任務(未定義項目資源,暫且略過);最後執行 compiler:compile 任務,將項目主代碼編譯至 target/classes 目錄(編譯好的類爲 com/wx/mvn/helloworld/HelloWorld.Class)。
下面介紹一些 Maven 倉庫工做的原理。典型的一個 Maven依賴下會有這三個文件:
maven-metadata.xml maven-metadata.xml.md5 maven-metadata.xml.sha1
maven-metadata.xml裏面記錄了最後deploy的版本和時間。
<?xml version="1.0" encoding="UTF-8"?> <metadata modelVersion="1.1.0"> <groupId>io.github.hengyunabc</groupId> <artifactId>mybatis-ehcache-spring</artifactId> <version>0.0.1-SNAPSHOT</version> <versioning> <snapshot> <timestamp>20150804.095005</timestamp> <buildNumber>1</buildNumber> </snapshot> <lastUpdated>20150804095005</lastUpdated> </versioning> </metadata>
其中 md5, sha1 校驗文件是用來保證這個 meta 文件的完整性。Maven 在編繹項目時,會先嚐試請求 maven-metadata.xml,若是沒有找到,則會直接嘗試請求到jar文件,在下載 jar 文件時也會嘗試下載 jar 的 md5, sha1 文件。Maven 的 repository 並無優先級的配置,也不能單獨爲某些依賴配置 repository。因此若是項目配置了多個repository,在首次編繹時,會依次嘗試下載依賴。若是沒有找到,嘗試下一個,整個流程會很長。因此儘可能多個依賴放同一個倉庫,不要每一個項目都有一個本身的倉庫。若是想要使用本地file倉庫裏,在項目的pom.xml裏配置,如:
<repositories> <repository> <id>hengyunabc-maven-repo</id> <url>file:/home/hengyunabc/code/maven-repo/repository/</url> </repository> </repositories>