自動化構建工具Maven
@[toc]
簡介
如今我們構建一個專案需要用到很多第三方的類庫,一個專案jar包的數量之多往往讓我們無法想象,並且jar包之間的關係錯綜複雜,一個jar包往往又會引用其他jar包,缺少任何一個jar包都會導致專案編譯失敗。以往開發專案時,人們往往需要花較多的精力在引用Jar包搭建專案環境上,而這一項工作尤為艱難,因為jar包之間的關係很複雜,當某些jar包無用後,又很難將其從中去除。而Maven就是一款幫助程我們構建專案的工具,我們只需要告訴Maven需要哪些jar 包,它會幫助我們下載所有的jar,極大提升開發效率。
Maven的核心概念
那麼既然你看到了這篇文章,我暫且就認為你對Maven有一定的瞭解並且已經完成了Maven的下載安裝和環境變數的配置。關於Maven的安裝配置網上教程有很多,我就不做重複的事情了,我們直接進入正題。來看看關於Maven的核心概念:
- 約定的目錄結構
- POM
- 座標
- 依賴
- 倉庫
- 生命週期
- 繼承
- 聚合
那麼,我麼就從這八個方面來深入學習一下Maven。
1.約定的目錄結構
對於目錄結構,Maven有著自己的規定,所以我們只需要瞭解Maven自動構建生成的目錄結構及其作用。
2.POM
POM(Project Object Model),專案物件模型。在Maven構建的專案中,pom.xml是核心配置檔案,與構建過程相關的一切設定都在這個檔案中進行配置。重要程式相當於web.xml對於Web工程。
3.座標
我們類比數學中的座標:在平面上,使用X、Y兩個向量可以唯一地定位平面上的任何一個點;在空間中,使用X、Y、Z三個向量可以唯一地定位空間中的任何一個點。那麼在Maven中,使用下面三個向量可以唯一地定位倉庫中的任何一個點。
- groupId:公司或組織域名倒序 + 專案名
- artifactId:專案名
- version:版本號
這是一個逐漸縮小範圍的定位,在現實生活中,你要郵寄一個快遞,你得先寫省份,然後寫市區,然後寫縣鄉,最後是具體哪棟樓或某個位置。我們看一個例子:在倉庫中有這樣一個jar包,我們如何來定位它呢?我們看到該資料夾下有一個pom檔案,我們開啟看一看:(截取了部分)我們只看關鍵部分,那麼在Maven中,工程的座標與倉庫中的路徑其實是一樣的,所以我們可以通過這三個向量組拼出一個路徑:
commons-logging/commons-logging-api/1.1/commons-logging-api-1.1.jar複製程式碼
jar檔案的命名規則是atrifactId - 版本號。而我們檢視倉庫目錄,發現jar檔案所處的檔案路徑確實如此,這就是Maven管理jar包的一個統一方式。
4.依賴
Maven解析依賴資訊時,會到本地倉庫中查詢被依賴的jar包。對於我們自己開發的Maven工程,使用install命令安裝後就可以進入倉庫。依賴中比較重要的一個概念是依賴範圍,依賴範圍可分為三類:
- compile
- test
- provided
在主程式中是無法看到測試程式的,但是在測試程式中能夠看到主程式,所以compile範圍對主程式和測試程式都有效,並且參與打包;而test範圍對主程式無效,對測試程式有效,不參與打包;provided範圍對主程式和測試程式都有效,但不參與打包。
這裡簡單提一提關於依賴的傳遞性:在工程中可以通過其它工程進行一個依賴的傳遞,可以傳遞的依賴不必在每個模組工程中都重複宣告,在最底部的工程中依賴一次即可。但是依賴中的傳遞也不是絕對的,例如非compile的依賴無法傳遞。相反地,依賴具有排除性。當你不想要某些jar包時,就需要設定依賴的排除方式:
<exclusions>
<exclusion>
<groupId></groupId>
<artifactId></artifactId>
</exclusion>
</exclusions>複製程式碼
這樣即可將jar包排除,但它只能在當前工程生效。依賴原則:
- 驗證路徑最短者優先
- 驗證路徑相同時先宣告者優先
5.倉庫
在Maven中,倉庫可分為兩類:
- 本地倉庫:當前電腦上部署的倉庫目錄,為當前電腦上所有Maven工程服務
- 遠端倉庫(遠端倉庫亦可分為三類):
- 私服:搭建在當前區域網環境下,為當前區域網範圍內的所有Maven工程服務
- 中央倉庫:架設在Internet上,為全世界所有Maven工程服務
- 中央倉庫映象:架設在各個大洲,為中央倉庫分擔流量,減輕中央倉庫的壓力,同時更快地響應使用者請求
而倉庫中儲存的內容就是Maven工程,可分為三類:
- Maven自身所需要的外掛
- 第三方框架或工具的jar包
- 自己開發的Maven工程
6.生命週期
Maven中的生命週期,其實就是各個構建環節的順序。構建環節:
- [1]清理:將以前編譯得到的舊的class位元組碼檔案刪除,為下一次編譯做準備
- [2]編譯:將Java源程式編譯成class位元組碼檔案
- [3]測試:自動測試,自動呼叫JUnit程式
- [4]報告:測試程式執行的結果
- [5]打包:動態Web工程打war包,Java工程打jar包
- [6]安裝:Maven中特定的概念——將打包得到的檔案複製到倉庫中的指定位置
- [7]部署:將動態Web工程生成的war包複製到Servlet容器的指定目錄下,使其能夠正常執行
這個構建順序不能夠被打亂,必須順序執行。Maven的核心程式中定義了抽象的宣告週期,生命週期中各個階段的具體任務是由外掛來完成的。Maven有三套相互獨立的生命週期,分別是:
- Clean Lifecycle:在進行真正的構建之前進行一些清理工作
- Default Lifecycle:構建的核心部分,編譯、測試、打包、安裝、部署等等
- Site Lifecycle:生成專案報告,站點,釋出站點
它們是相互獨立的,你可以僅僅呼叫clean來清理工作目錄,僅僅呼叫site來生成站點,當然你也可以直接執行mvn clean install site執行所有這三套生命週期。關於每套生命週期的具體內容不做分析。而Maven核心程式為了更好地實現自動化構建,按照這一特點執行生命週期的各個階段:不論現在要執行生命週期中的哪一階段,都是從這個生命週期最初的位置開始執行。
7.繼承
假設一個情景:Hello專案依賴的JUnit版本:4.0Hello2專案依賴的JUnit版本:4.0Hello3專案依賴的JUnit版本:4.9由於test範圍的依賴不能傳遞,所以必然會分散在各個模組中,很容易產生版本不一致的問題。那麼我們就可以將JUnit依賴版本統一提取到父工程,在子工程中宣告依賴時不指定版本即可,那麼子工程將會以父工程中統一設定的版本為準,同時也便於修改。注意如果一個工程作為父工程,打包方式應為pom。在子工程中使用parent標籤來宣告父類的引用。
8.聚合
作用:一鍵安裝各個模組工程配置方式:在一個總的聚合工程中配置各個參與聚合的模組。通過models標籤進行配置。然後只需在聚合工程上執行安裝命令即可一鍵安裝所有模組工程。
Maven外掛的設定
前面說了這麼多關於Maven的理論知識,不光自己說得口乾舌燥,看的人肯定也已經暈頭轉向了。但是沒辦法, 基礎知識我們得掌握,然後才能在實際運用中更加得心應手。那麼接下來我們就實際操作一下Maven工程,這裡以eclipse為例。首先是Maven外掛的設定:只要不是版本特別老的eclipse,它都已經內建了Maven外掛,我們只需要設定一下即可。點選Windows,然後選擇Preferences開啟首選項視窗。我們點選Installations設定一下Maven的路徑,eclipse會內建一個Maven,但通常認為內建的Maven不夠好,不夠穩定,所以我們點選Add,然後找到我們自己下載的Maven,新增進去即可。然後User Setting用於指定Maven倉庫的位置,eclipse預設會自己找到。設定完畢後,我們在eclipse中建立一個Maven版的Java工程:右鍵->New->Other->找到Maven Project->Next該Java工程預設會有一個JDK版本,如果想直接修改預設JDK版本,可以來到Maven安裝目錄下的conf目錄,開啟settings.xml檔案,找到profiles標籤,然後在裡面新增:
<profile>
<id>jdk-1.7</id>
<activation>
<activeByDefalut>true</activeByDefalut>
<jdk>1.7</jdk>
</activation>
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<maven.compiler.compilerVersion>1.7</maven.compiler.compilerVersion>
</properties>
<profile>複製程式碼
那麼接下來演示一下如何建立Web工程:具體建立的是什麼工程,其實是由Packaging決定,如果選的是jar,則建立Java工程;如果選的是war,則建立Web工程。那麼可以看到的是,Maven構建的Web工程並沒有web.xml檔案,導致工程報錯,webapp下也沒有任何東西,顯然這個Web工程是不完整的,我們來解決這一問題。右鍵點選工程,然後選擇Properties,開啟配置視窗:點選Projecy Facets,會發新Dynamic Web Module預設是選中的,我們把勾去掉,接著點選Apply,然後又把勾打上,這時你會發現下面多出了一個選項,我們點選開啟視窗:按照上面的進行修改,然後點選OK。現在專案就不報錯了。然而當你在webapp目錄下新建了一個jsp檔案後,專案又報錯了。這是因為專案中缺少Apache Tomcat的執行環境,那怎麼解決呢?開啟pom.xml,我們知道,HttpServlet在servlet-api的jar包下,那麼我們就可以通過pom檔案進行該jar包的匯入,在pom.xml檔案中新增下面的依賴:
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>複製程式碼
點選儲存後專案立馬就不報錯了。然後我們執行一下程式,程式正確執行,接著來到部署目錄下,發現lib目錄是空的。這是因為依賴的範圍是provided,如果我們將依賴範圍設定為compile,再執行看效果。這時候jar包就被下載到了lib目錄。這也解釋了上面說的依賴範圍關係。現在我們來到index.jsp檔案編寫一條EL表示式:會發現pageContext後面沒有提示而request有,這是因為request是serlvet-api包下的,而這個jar包我們在剛才已經匯入了,所以,我們只需要匯入pageContext所在的jar包即可,在pom檔案下新增一條依賴:
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1.3-b06</version>
<scope>provided</scope>
</dependency>複製程式碼
現在pageContext的提示就出來了。關於依賴的範圍問題要尤為重視,如果你將jsp-api的範圍設定為compile,專案執行後會產生一個空指標異常,顯然這個異常不是我們的程式碼產生的,因為我們壓根就沒寫什麼程式碼。如果依賴範圍設定為了compile,我們知道jar包是會被下載到lib目錄下的,而jsp-api需要依賴兩個jar包,這樣總共就下載了三個jar包,而這些jar包在Tomcat中也存在。此時這些jar包就會產生衝突,從而造成一些無法理解的錯誤。所以依賴範圍一定要嚴謹。
統一管理依賴的版本
假如我們在做一個專案,一開始使用的是spring4.0的版本,但是後面我們需要對jar包進行升級,將版本升級為5.0,該如何升級呢?我們知道,spring框架所依賴的jar包非常多,一個一個地在pom檔案中進行修改顯然不合理。那麼在pom中,我們有一個很好的配置方式:[1]使用properties標籤內部使用自定義標籤統一宣告版本號[2]在需要統一版本的位置,使用${自定義標籤名}引用宣告的版本號
常用Maven命令
注意:執行與構建過程相關的Maven命令,必須進入pom.xml檔案所在的目錄。常用命令:
- [1]mvn clean:清理
- [2]mvn compile:編譯主程式
- [3]mvn test-compile:編譯測試程式
- [4]mvn test:執行測試
- [5]mvn package:打包
- [6]mvn install:安裝
- [7]mvn site:生成站點
然而關於這些jar包的依賴資訊我們不可能能夠熟記,而事實上我們也不需要去記,只是在需要的時候上網搜尋一下即可。貼上一個查詢依賴資訊的網站:https://mvnrepository.com/ 需要什麼jar包的依賴資訊,只需在搜尋框輸入然後搜尋即可。