自動化構建工具Maven
- 2020 年 2 月 14 日
- 筆記
文章目錄
- 簡介
- Maven的核心概念
- 1.約定的目錄結構
- 2.POM
- 3.坐標
- 4.依賴
- 5.倉庫
- 6.生命周期
- 7.繼承
- 8.聚合
- Maven插件的設置
- 統一管理依賴的版本
- 常用Maven命令
簡介
如今我們構建一個項目需要用到很多第三方的類庫,一個項目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.0 Hello2項目依賴的JUnit版本:4.0 Hello3項目依賴的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包的依賴信息,只需在搜索框輸入然後搜索即可。
