「Maven」 是 Apache 下的一個純 Java 開發的開源專案。基於專案物件模型(縮寫:POM)概念,Maven利用一箇中央資訊片斷能管理一個專案的構建、報告和文件等步驟、依賴管理。Maven 的本質是一個專案管理工具,開發人員只需做一些簡單的設定,就可以批次完成專案的構建、報告和文件的生成工作。Maven 是跨平臺的,這意味着無論是在 Windows 上,還是在 Linux 或者 Mac 上,都可以使用同樣的命令。
該目錄包含了 mvn 執行的指令碼,這些指令碼用來設定 Java 命令,準備好 classpath 和相關的 Java 系統屬性,然後執行 Java 命令。
其中 mvn 是基於 UNIX 平臺的 shell 指令碼,mvn.bat 是基於 Windows 平臺的 bat 指令碼。在命令列輸入任何一條 mvn 命令時,實際上就是在呼叫這些指令碼。
該目錄還包含了 mvnDebug 和 mvnDebug.bat 兩個檔案,同樣,前者是 UNIX 平臺的 shell 指令碼,後者是 Windows 平臺的 bat 指令碼。
該目錄只包含一個檔案,以 maven 3.6.1 爲例,該檔案爲 plexus-classworlds-2.6.0.jar。
plexus-classworlds 是一個類載入器框架,相對於預設的 java 類載入器,它提供了更豐富的語法以方便設定,Maven 使用該框架載入自己的類庫。
該目錄包含了一個非常重要的檔案 settings.xml。直接修改該檔案,就能在機器上全域性地定製 Maven 的行爲。
一般情況下,我們更偏向於複製該檔案至 ~/.m2/ 目錄下(~表示使用者目錄),然後修改該檔案,在使用者範圍定製 Maven 的行爲。後面將會多次提到 settings.xml,並逐步分析其中的各個元素。
該目錄包含了所有 Maven 執行時需要的 Java 類庫,Maven 本身是分模組開發的,因此使用者能看到諸如 maven-core-3.0.jar、maven-model-3.0.jar 之類的檔案。
此外,這裏還包含一些 Maven 用到的第三方依賴,如 common-cli-1.2.jar、commons-lang-2.6.jar 等。
對於 Maven 2 來說,該目錄只包含一個如 maven-2.2.1-uber.jar 的檔案,原本各爲獨立 JAR 檔案的 Maven 模組和第三方類庫都被拆解後重新合併到了這個 JAR 檔案中。可以說,lib 目錄就是真正的 Maven。關於該檔案,還有一點值得一提的是,使用者可以在這個目錄中找到 Maven 內建的超級 POM
記錄了 Maven 使用的軟體許可證Apache License Version 2.0。
記錄了 Maven 包含的第三方軟體。
包含了 Maven 的簡要介紹,包括安裝需求及如何安裝的簡要指令等。
Maven 擁有三套獨立的生命週期,它們分別是 clean、default 和 site。clean 生命週期的目的是清理專案;default 生命週期的目的是構建專案;site 生命週期的目的是建立專案站點。
每個生命週期又包含了多個階段。這些階段在執行的時候是有固定順序的。後面的階段一定要等前面的階段執行完成後才能 纔能被執行。
比如 clean 生命週期,它就包含 pre-clean、clean 和 post-clean 三個階段。使用者呼叫 pre-clean 時,只有 pre-clean 階段被執行;呼叫 clean 時,先執行 pre-clean,再執行 clean 階段;同理,當呼叫 post-clean 時,Maven 自動先執行 pre-clean、再執行 clean,最後執行 post-clean。
clean 生命週期的目的是清理專案,它包括以下三個階段。
default 生命週期定義了構建專案時所需要的執行步驟,它是所有生命週期中最核心部分,包含的階段如下表所述,比較常用的階段用粗體標記。
預設生命週期:校驗-初始化-編譯-測試-打包-整合測試-安裝-部署
validate-initialize-compile-test-package-integrationTest-install-deploy
site 生命週期的目的是建立和發佈專案站點。Maven 可以基於 pom 所描述的資訊自動生成專案的站點,同時還可以根據需要生成相關的報告文件整合在站點中,方便團隊交流和發佈專案資訊。site 生命週期包括如下階段。
前面介紹了每套生命週期的各個階段,那怎樣通知 Maven 執行生命週期的哪個階段呢?
有兩種方式可以同 Maven 進行互動,一種是用 mvn 命令;另一種是在 M2Eclipse 中,使用對應的 Run As 選單命令。
這種方式都是在 CMD 命令列視窗中執行的,前提條件是要設定好安裝的 Maven 環境變數(Path),並且將當前目錄切換到 Maven 工程目錄下。後面每個命令的例子都是基於 MvnSSMDemo.Service.Impl 工程進行的,它的當前目錄是 E:\temp\demoMaven\MvnSSMDemo.Service.Impl。
1)mvn clean:呼叫 clean 生命週期的 clean 階段,實際執行的是 clean 生命週期中的 pre-clean 和 clean 階段,如圖 所示。
2)mvn test:該命令呼叫 default 生命週期中的 test 階段。實際執行的階段包括 validate、initialize、generate-sources…compile…test-compile、process-test-classes、test,也就是把 default 生命週期中從開始到 test 的所有階段都執行完了,而且是按順序執行。最後執行效果如圖所示。
3)mvn clean install:該命令呼叫 clean 生命週期的 clean 階段和 default 生命週期的 install 階段。
實際執行的是 clean 生命週期中的 pre-clean、clean 兩個階段和 default 生命週期中從開始的 validate 到 install 的所有階段。
該命令結合了兩個生命週期。在實際專案構建中,每執行一個行的構建,先清理以前構建的舊檔案是一個好習慣。最後執行效果如圖 3 所示。
4)mvn clean deploy site-deploy:該命令呼叫 clean 生命週期中的 pre-clean、clean 階段,default 生命週期中從 validate 到 deploy 的所有階段,以及 site 生命週期中的 pre-site、site、post-site 和 site-deploy 階段。
最後的結果是把該專案編譯、測試、打包好發佈到遠端倉庫,同時還將生成好的站點發布到站點伺服器。
在 Maven 倉庫中,是用座標標記來一一對應地管理每個構件的。一個完整的座標資訊,由 groupId、artifactId、version、packaging、classifier 組成,如下是一個簡單的座標定義。
<groupId>org.SpringFramework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.7.RELEASE</version>
<packaging>jar</packaging>v
定義當前 Maven 專案從屬的實際專案。關於 groupId 的理解如下所示。
1)Maven 專案和實際專案不一定是一一對應的。比如 SpringFramework,它對應的 Maven 專案就有很多,如 spring-core、spring-context、spring-security 等。造成這樣的原因是模組的概念,所以一個實際專案經常會被劃分成很多模組。
2)groupId 不應該同開發專案的公司或組織對應。原因比較好理解,一個公司和一個組織會開發很多實際專案,如果用 groupId 對應公司和組織,那 artifactId 就只能是對應於每個實際專案了,而再往下的模組就沒法描述了,而往往專案中的每個模組是以單獨的形式形成構件,以便其他專案重複聚合使用。
3)groupId 的表述形式同 Java 包名的表述方式類似,通常與域名反向一一對應。
定義實際專案中的一個 Maven 專案(實際專案中的一個模組)。
推薦命名的方式爲:實際專案名稱-模組名稱。
比如,org.springframework 是實際專案名稱,而現在用的是其中的核心模組,它的 artifactId 爲 spring-core。
定義 Maven 當前所處的版本。如上的描述,用的是 4.2.7.RELEASE 版本。需要注意的是,Maven 中對版本號的定義是有一套規範的。
定義 Maven 專案的打包方式。
打包方式通常與所生成的構件檔案的擴充套件名對應,比如,.jar、.ear、.war、.pom 等。另外,打包方式是與工程構建的生命週期對應的。比如,jar 打包與 war 打包使用的命令是不相同的。最後需要注意的是,可以不指定 packaging,這時候 Maven 會自動預設成 jar。
定義構件輸出的附屬構件。
附屬構件同主構件是一一對應的,比如上面的 spring-core-4.2.7.RELEASE.jar 是 spring-core Maven spring-core 專案的主構。
Maven spring-core 專案除了可以生成上面的主構件外,也可以生成 spring-core-4.2.7.RELEASE-javadoc.java 和 spring-core-4.2.7.RELEASE-sources.jar 這樣的附屬構件。這時候,javadoc 和 sources 就是這兩個附屬構件的 classifier。這樣就爲主構件的每個附屬構件也定義了一個唯一的座標。
最後需要特別注意的是,不能直接定義一個 Maven 專案的 classifier,因爲附屬構件不是由 Maven 專案構建的時候直接預設生成的,而是由附加的其他外掛生成的。
前面介紹的組成座標的 5 個要素中,groupId、artifactId 和 version 是必需的,packaging 是可選的,預設是 jar,而 classifier 是不能直接定義的。同時,Maven 專案的構件檔名與座標也是有對應關係的,一般規則是 artifactId-version[-classifier].packaging。
在 Maven 中,所有的依賴、外掛以及 Maven 專案構建完的輸出都是以構件的形式存在的,都叫構件。任何一個構件都是由一組座標資訊唯一標識的。
在一臺用於專案開發的計算機中有可能存在很多 Maven 專案,比如前面介紹的那麼多樣例程式碼,它們都是分佈在不同的 Maven 專案中的。這些 Maven 專案肯定都會用到 compiler 外掛,除了這個外掛外,還有很多特有的構件。比如,MvnSSHDemo.Struts 中就用到了 struts2 構件,MvnSSH.Spring 中就用到了 Spring 相關的構件,MvnSSM.SpringMVC 中用到了 Spring-web 構件等。而且這些直接依賴中,又會引入很多間接依賴,中間也肯定有交叉的構件依賴在參照。
如果同以前的開發模式一樣,將各自用到的依賴對應的構件檔案都體現到自己的對應目錄,比如 lib 目錄下的話,就會發現同樣的檔案會在很多工程裏面重複存在。這樣不僅造成了大量的磁碟空間浪費,也不便於統一管理。
所以Maven 統一儲存了所有 Maven 專案用到的構件,這些構件都是共用的。當某個 Maven 專案要使用某些構件的時候,就直接通過構件的座標參照共用的構件,不需要複製到每個 Maven 工程的獨立物理目錄中去。這個統一的位置就叫***倉庫***
Maven 的倉庫,實際上就是 Maven 構件的公共倉庫。在實際的 Maven 專案中,只需指明這些依賴的座標,需要的時候(編譯、測試、執行),由 Maven 自動根據座標找到對應的構件後使用。爲了完全實現重用,Maven 專案構建完畢後生成的構件也可以安裝或部署到倉庫中,供其他 Maven 專案使用。
使用者可以從中央倉庫中找到絕大部分流行的構件,但是畢竟不能找到所有構件。對那些在中央倉庫中沒有的構件,又要怎麼辦呢?可以在 pom.xml 中新增另外一個遠端倉庫。比如,將 jboss Maven 遠端倉庫新增到 Maven,需要在 Maven 工程的 pom.xml 中新增如下設定。
<project>
...
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Maven Repository</name>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
...
</project>
Maven 爲什麼要新增一個快照版本的控制呢?
假設張三在開發使用者管理模組的 1.1 版本,該版本還沒有正式發佈。以前的使用者管理模組和許可權管理模組是由李四在單獨開發的。其中,許可權管理模組的功能是依賴使用者管理模組的。
在開發過程中,張三經常要將最新的使用者管理模組構建輸出,交給李四,讓他對許可權管理模組進行開發整合和偵錯。這種問題,如果由使用者自己手動控制的話,相對比較麻煩。但 Maven 基於快照機制 機製,就能自動解決這個問題。
基於 Maven 的快照機制 機製,張三隻需將使用者管理模組的版本設定成 1.1-SNAPSHOT,然後發佈到私服中。
在發佈過程中,Maven 會自動爲構件打上時間戳,比如 1.1-20161211.111111-11,表示 2016 年 12 月 11 日 11 點 11 分 11 秒的第 11 次的快照。有了這個時間戳,Maven 就能隨時找到倉庫中使用者管理構件 1.1-SNAPSHOT 版本的最新檔案。
這時,李四設定對使用者管理模組的 1.1-SNAPSHOT 版本的依賴,當他構建許可權管理模組的時候,Maven 會自動從倉庫中檢測使用者管理 1.1-SNAPSHOT 的最新構件,發現最新構件後就自動下載。
Maven 預設情況下,每天檢測一次(具體實際情況,由參考設定的 updatePolicy 控制),當然,也可以使用 mvn-U 強制讓 Maven 檢測更新。如 mvn clean install-U。
基於這樣的機制 機製,張三在構建成功後,將構件發佈到倉庫,李四可以完全考慮使用者管理模組的構件,並且他還能確保隨時得到使用者管理模組的最新可用的快照構件,這些所有的一切都由 Maven 自動完成。
快照版本只應該在開發團隊內部的專案或模組之間依賴使用。這個時候,團隊成員對這些快照版本的依賴具有完全的理解和控制權利。
依賴一般分以下兩個層次理解:
1)在 Maven 專案的 pom.xml 中設定所需要構件的座標,也就是設定依賴。還有就是 Maven 在構建專案的時候,根據座標從倉庫中找到座標所對應的構件檔案,並且把它們引入 Maven 專案中來,也就是 Maven 參照。
2)由 Maven 構建的時候自己搞定。前面也介紹了 Maven 基於座標尋找要執行的外掛的思路。實際上,外掛本身就是一個特殊的構件。查詢外掛的思路也就是依賴查詢的思路。這裏需要把握的更多的是第一層次,即怎樣設定依賴,以及指定依賴內部的關係和優化等。
掌握依賴,從設定開始。接下來介紹一下依賴的設定。依賴是設定在 pom.xml 中的,如下是關於依賴設定的大概內容:
<project>
...
<dependencies>
<dependency>
<groupId>...</groupId>
<artifactId>
...
</artifactId>
<version>...</version>
<type>...</type>
<scope>...</scope>
<optional>...</optional>
<exclusions>
<exclusion>...</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>
Java 中有個環境變數叫 classpath。JVM 執行程式碼的時候,需要基於 classpath 查詢需要的類檔案,才能 纔能載入到記憶體執行。
Maven 在編譯專案主程式碼的時候,使用的是一套 classpath,主程式碼編譯時需要的依賴就新增到這個 classpath 中去;Maven 在編譯和執行測試程式碼的時候,又會使用一套 classpath,這個動作需要的依賴就新增到這個 classpath 中去;Maven 專案具體執行的時候,又有一個獨立的 classpath,同樣執行時需要的依賴,肯定也要加到這個 classpath 中。這些 classpath,就是依賴的範圍。
依賴的範圍,就是用來控制這三種 classpath 的關係(編譯 classpath、測試 classpath 和執行 classpath),接下來分別介紹依賴的範圍的名稱和意義。
編譯依賴範圍。如果在設定的時候沒有指定,就預設使用這個範圍。使用該範圍的依賴,對編譯、測試、執行三種 classpath 都有效。
測試依賴範圍。使用該範圍的依賴只對測試 classpath 有效,在編譯主程式碼或執行專案的時候,這種依賴是無效的。
已提供依賴範圍。使用此範圍的依賴,只在編譯和測試 classpath 的時候有效,執行專案的時候是無效的。比如 Web 應用中的 servlet-api,編譯和測試的時候就需要該依賴,執行的時候,因爲容器中自帶了 servlet-api,就沒必要使用了。如果使用了,反而有可能出現版本不一致的衝突。
執行時依賴範圍。使用該範圍的依賴,只對測試和執行的 classpath 有效,但在編譯主程式碼時是無效的。比如 JDBC 驅動實現類,就需要在執行測試和執行主程式碼時候使用,編譯的時候,只需 JDBC 介面就行。
系統依賴範圍。該範圍與 classpath 的關係,同 provided 一樣。但是,使用 system 存取時,必須通過 systemPath 元素指定依賴檔案的路徑。因爲該依賴不是通過 Maven 倉庫解析的,建議謹慎使用。
如下程式碼是一個使用 system 範圍的案例。
<dependency>
<groupId>xxx</groupId>
<artifactId>xxx</artifactId>
<version>xx</version>
<scope>system</scope>
<systemPath>e:/xxxx/xxx/xx.jar</systemPath>
</dependency>
匯入依賴範圍。該依賴範圍不會對三種 classpath 產生實際的影響。它的作用是將其他模組定義好的 dependencyManagement 匯入當前 Maven 專案 pom 的 dependencyManagement 中。比如有個 SpringPOM Maven 工程,它的 pom 中的 dependencyManagement 設定如下:
<project>
...
<groupId>cn.com.mvn.pom</groupId>
<artifactId>SpringPOM</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
...
<dependencyManagement>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${project.build.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${project.build.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${project.build.spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
...
</project>
接下來建立一個新的 Maven 工程 Second,要將 First 工程中 pom 中定義的 dependency-Management 原樣合併過來,除了複製、繼承之外,還可以編寫如下程式碼,將它們匯入進去。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.com.mvn.pom</groupId>
<artifactId>SpringPOM</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在使用 Maven 之前,如果要基於 Spring 框架開發專案,除了要加入 Spring 框架的 jar 包外,還需要將 Spring 框架所用到的第三方 jar 包加入。否則編譯通過,但是執行的時候就會出現 classNotFound 異常。
爲了解決這種問題,一般有兩種方式:一種是下載 Spring 的 dependencies.zip 包,將其中的所有 jar 包都匯入工程;另一種是根據執行時的報錯資訊,確定哪些類沒有,再將包含這些類的 jar 包下載下來匯入。
第一種方式雖然可以一次性解決所有需要 jar 包的匯入問題,但是當檢視工程的 jar 包會發現,有不少多餘的 jar 包。這些多餘的 jar 包不僅僅加大了專案的體積,還有可能同其他框架所匯入的 jar 包有版本衝突。
第二種方式雖然不會有多餘的 jar 包存在,但是要根據每次啓動的錯誤,一個個找到 jar 包,再匯入。想象如果有 10 個 jar 包,就要啓動 10 次,檢視 10 次錯誤分別匯入,有多麻煩。
Maven 的傳遞依賴機制 機製就能解決這樣的問題。
當專案基於 Spring 框架實現的時候,只需將 Spring 的依賴設定到 pom 的依賴元素就行。至於 Spring 框架所依賴的第三方 jar 包,使用者不用處理,Maven 自己通過檢測 Spring 框架的依賴資訊將它們匯入專案中來。而且只會匯入 Spring 框架所需要的,不會匯入多餘的依賴。
也就是說,Maven 會解析專案中的每個直接依賴的 pom,將那些必要的間接依賴以傳遞依賴的形式引入專案中。
當然,傳遞依賴在將間接依賴引入專案的過程中也有它自己的規則和範圍。這個規則和範圍是同前面介紹的依賴範圍緊密關聯的。
現在有三個專案(A、B 和 C 專案),假設 A 依賴 B,B 依賴 C,這樣把 A 對 B 的依賴叫第一直接依賴,B 對 C 的依賴叫第二直接依賴,而 A 對 C 的依賴叫傳遞依賴(通過 B 傳遞的)。
中間 A 到 B 第一直接依賴的範圍和 B 到 C 第二直接依賴的範圍,就共同決定了 A 到 C 的傳遞依賴範圍。它們的影響效果,就如表 1 所示。
座標第一列表示第一直接依賴的範圍,第一行表示第二直接依賴的範圍,中間的交叉點爲共同影響後的傳遞依賴的範圍。
依賴 | compile | test | provided | runtime |
---|---|---|---|---|
Compile | compile | – | – | runtime |
test | test | – | – | test |
provided | provided | – | provided | provided |
runtime | runtime | – | – | runtime |
通過前面的表格,可以得出如下規律。
在使用 Maven 自動提供的傳遞依賴後,可以解決對應的依賴管理,特別是間接依賴管理中遇到的問題。但是,當多個直接依賴都帶來了同一個間接依賴,而且是不同版本的間接依賴時,就會引起重複依賴,甚至包衝突的問題。
那麼,Maven 在傳遞依賴的時候是按什麼規則來的呢?
Maven 依賴調解原則有兩個:一個是路徑優先原則;另一個是宣告優先原則。當路徑優先原則搞不定的時候,再使用宣告優先原則。
比如有個專案 A,它有兩個依賴:A→B→C→T(1.0),A→D→T(2.0)。會發現,A 最終對 T(1.0)和 T(2.0)都有間接依賴。這時候 Maven 會自動判斷它的路徑,發現 T(2.0)的路徑長度爲 2,T(1.0)的路徑長度爲 3,以最短路徑爲原則,將 T(2.0)引入當前專案 A。
如果有個專案 A,它有兩個依賴:A→B→T(1.0),A→C→T(2.0)。這時候兩條路徑都是一樣的長度 2,那 Maven 到底把哪個引入專案 A 呢?這時候 Maven 會判斷哪個依賴在 pom.xml 中先宣告,選擇引入先宣告的依賴。
在實際專案中,存在一些比較特殊的依賴。比如數據存取層模組對數據庫驅動的依賴就比較特殊了。DAO 層要存取數據庫的時候,需要加入數據庫驅動依賴,而且不同數據庫驅動依賴是不一樣的。如果在設計 DAO 層的時候,是按跨數據庫標準實現的,這就引出了一個新問題,是在 pom.xml 中設定 MySQL 驅動依賴呢?還是設定 Oracle 驅動依賴?或者兩個都設定?
其實仔細想想,前面三種選項都不合適。單獨設定 MySQL 或 Oracle,這樣就不能跨數據庫了。兩個數據庫都設定,驅動之間就會有衝突,或有多餘的依賴。
這時候,就直接把這兩個數據庫驅動的依賴都設定成可選依賴,程式碼如下:
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.4</version>
<optional>true</optional>
</dependency>
</dependencies>
在應用專案中再具體指定使用哪個依賴,例如:
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
</dependencies>
需要說明的是,在實際專案中建議不要使用可選依賴。雖然可選依賴滿足了對一個模組的特徵多樣性,同時還提供了更多的選擇,但是在實際設定中,好像不僅沒有減少設定程式碼,還增多了重複複製的機會。
同時從物件導向分析和設計的思路來說,也是建議遵循單一職責原則,也就是一個類只有一個功能,不要糅合太多的功能,這樣不方便理解、開發和維護。
所以實際專案中,一般對不同數據庫的驅動單獨建立一個 Maven 工程。其他專案需要基於哪個數據庫進行操作的話,參照對應的 Maven 的工程以來就行,用傳遞依賴引入需要的數據庫驅動依賴。
Maven 專案同 MyEclipse 或其他工具產生的專案一樣,有自己的目錄結構和特殊的意義。
比如一般有如下目錄。
當然,還有一個 pom.xml 檔案,該檔案設定 Maven 管理的所有內容。
這裏可以按 Maven 的要求,自動建立目錄結構,按 Maven 的要求新增專案相關的組態檔,這樣確實可以實現,但是很煩瑣。已經有人用程式碼將這些要做的事情全都封裝實現了,如同在 MyEclipse 中建立工程的那種圖形化導向頁面一樣(這種效果到使用 MyEclipse+Maven 的時候體現),只要按它的步驟輸入資訊和命令,完成後自動產生專案架構。
這裏簡單介紹一下有關的命令和資訊。
1)命令。命令很簡單,就是建立專案的命令 create。
人們把要呼叫哪個軟體的 create 命令建立專案叫外掛(plugin)。建立專案的外掛叫 Archetype 外掛(archetype-plugin)。
2)資訊。和專案相關的資訊包括 groupId(組 Id)、artifactId(構件 Id)、packageName(包名)、version(版本)。
其實 packageName 和 version 好理解。程式設計師寫的類,肯定要放在一個標準包下或標準包的子包下,packageName 指標準包;version 是當前程式碼的版本號。
這裏的 groupId 和 artifactId 同部門名稱和組名稱一樣,用來唯一確定一個專案(軟體、功能)。有些地方會把這兩個描述的資訊合起來叫「座標」。
用命令產生專案的方式有兩種。
1)在硬碟上建立一個空的目錄,用來存放Maven專案,如E:\temp\demoMaven。
2)開啓 CMD 視窗,用 cd 命令,切換到 demoMaven 目錄,如圖所示
3)在 CMD 視窗中輸入「mvn archetype:generate」,按 Enter 鍵。
聯網初始化一段時間後(一般不少於 5 分鐘),會一步步提示輸入 groupId、artifactId、version、packageName 等資訊。最後建立成功,而且可以在 E:\temp\demoMaven 空目錄下發現一個同 artifactId 一樣的目錄,這就是建立的專案目錄。
1)在硬碟上建立一個空的目錄,用來存放 Maven 專案,如 E:\temp\demoMaven。
2)開啓 CMD 視窗,用 cd 命令,切換到 demoMaven 目錄,如圖 1 所示。
3)在 CMD 視窗中輸入如下命令並按 Enter 鍵。
mvn org.apache.maven.plugins:maven-archetype-plugin:2.2:creat
-DgroupId=com.mengma.demo
-DartifactId=HelloWorld
-DpackageName=com.mengma.demo
注:
Maven 執行命令的時候,會在本地尋找是否有指定版本的 Archetype 外掛,如果沒有,就需要聯網下載。最後顯示的正常狀態如圖所示。
同時,它會在 demoMaven 目錄下建立一個新的 HelloWorld 目錄。到這裏,就可以使用 Archetype 外掛建立第一個工程的架構了。
爲了完成體驗,需要寫兩個程式碼:一個是 HelloWorld.java,放在 src\main\java 目錄下;另一個是 TestHelloWorld.java,用來體現測試,放在 src\test\java 目錄下。下面 下麪介紹它們的內容。
HelloWorld.java 程式碼如下所示:
package com.mengma.demo.mvn;
/**
* 這是爲了研究Maven,寫的第一個Java程式碼 功能很簡單,輸出一個HelloWorld的問候
*
* @ author Noble
* @ version 1.0
*/
public class HelloWorld {
/**
* 輸出問候
* @ param name String,說話人名稱
* @ return String 格式是:xxx say HelloWorld
**/
public String say(String name) {
return name + " say HelloWorld";
}
}
TestHelloWorld.java 程式碼如下所示:
package com.mengma.demo.mvn;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestHelloWorld {
private HelloWorld hello;
@Before
public void init() {
hello = new HelloWorld();
}
@Test
public void testSay() {
String name = "張三";
String exp = "張三" + "say HelloWorld";
String act = hello.say(name);
Assert.assertEquals(exp, act);
}
@After
public void destory() {
hello = null;
}
}
程式碼寫好了,接下來要通過組態檔讓 Maven 管理。這時要用到 pom.xml,即骨架檔案。該檔案在建立工程時會在工程目錄下自動生成 pom.xml。
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mengma.demo</groupId>
<artifactId>HelloWorld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>HelloWorld</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
注:
開啓 CMD 視窗,操作步驟如下所示:
將目錄切換到工程目錄下(HelloWorld)。
輸入「mvn clean」,按 Enter 鍵清空以前編譯安裝過的歷史結果。
輸入「mvn compile」,按 Enter 鍵編譯原始碼。
輸入「mvn test」,按 Enter 鍵執行測試案例進行測試。
輸入「mvn install」,按 Enter 鍵,將當前程式碼打成 jar 包,安裝到 Maven 的本地管理目錄下,其他 Maven 工程只要指定座標就可以使用。
junit
4.7
test
注:
- 建立工程時指定的 groupId。
- 建立工程時指定的 artifactId。
- 當前工程的版本。
- 工程編譯好後,打成 jar 包安裝發佈。
- 測試時需要依賴的 JUnit 的 groupId。
- 測試時需要依賴的 JUnit 的 artifactId。
- 測試時需要依賴的 JUnit 的版本。
- 指定測試依賴的作用範圍是測試。
## 編譯和測試
開啓 CMD 視窗,操作步驟如下所示:
1. 將目錄切換到工程目錄下(HelloWorld)。
2. 輸入「mvn clean」,按 Enter 鍵清空以前編譯安裝過的歷史結果。
3. 輸入「mvn compile」,按 Enter 鍵編譯原始碼。
4. 輸入「mvn test」,按 Enter 鍵執行測試案例進行測試。
5. 輸入「mvn install」,按 Enter 鍵,將當前程式碼打成 jar 包,安裝到 Maven 的本地管理目錄下,其他 Maven 工程只要指定座標就可以使用。
到現在爲止,編碼的操作就完成了,包括工程的建立、原始碼的編寫、單元測試程式碼的編寫、程式碼的編譯、測試案例的執行以及最後的打包。