寫在前面: 作爲一個大一學生,最近肝的有點多,今天寫一下Maven的一些基礎與使用的學習筆記,整理了很久,若有錯誤請大佬原諒。 希望有些內容能夠對初學者有幫助。
公衆號:小白編碼
什麼是Maven
一個對Maven比較正式的定義是這麼說的:Maven是一個項目管理工具,它包含了一個項目對象模型 (POM:Project Object Model),一組標準集合,一個項目生命週期(Project Lifecycle),一個依賴管理系統(Dependency Management System),和用來運行定義在生命週期階段(phase)中插件(plugin)目標(goal)的邏輯。
Maven是幹什麼的?
即使不使用Maven 我們仍然可以進行B/S 結構項目的開發。從表述層、業務邏輯層到持久化層再到數據庫都有成熟的解決方案。
其實Maven 並不是直接用來輔助編碼的,它戰鬥的崗位並不是以上各層。所以我們有必要通過企業開發中的實際需求來看一看哪些方面是我們現有技術的不足。
Maven所解決的問題
1、我們需要引用各種jar包,尤其是比較大的工程,引用的jar包往往有幾十個乃至上百個, 每用到一種jar包,都需要手動引入工程目錄,而且經常遇到各種讓人抓狂的jar包衝突,版本衝突。
2、我們辛辛苦苦寫好了Java文件,可是隻懂0和1的白癡電腦卻完全讀不懂,需要將它編譯成二進制字節碼。好歹現在這項工作可以由各種集成開發工具幫我們完成,Eclipse、IDEA等都可以將代碼即時編譯。當然,如果你嫌生命漫長,何不鋪張,也可以用記事本來敲代碼,然後用javac命令一個個地去編譯,逗電腦玩。
3、世界上沒有不存在bug的代碼,計算機喜歡bug就和人們總是喜歡美女帥哥一樣。爲了追求美爲了減少bug,因此寫完了代碼,我們還要寫一些單元測試,然後一個個的運行來檢驗代碼質量。
4、再優雅的代碼也是要出來賣的。我們後面還需要把代碼與各種配置文件、資源整合到一起,定型打包,如果是web項目,還需要將之發佈到服務器,供人蹂躪。
Maven就可以幫你構建工程,管理jar包,編譯代碼,還能幫你自動運行單元測試,打包,生成報表,甚至能幫你部署項目,生成Web站點。
Maven的優勢舉例
Web項目,要能夠將項目運行起來,就必須將該項目所依賴的一些jar包添加到工程中,否則項目就不能運行。 試想如果具有相同架構的項目有十個,那麼我們就需要將這一份jar包複製到十個不同的工程中。我們一起來看一個CRM項目的工程大小。
使用傳統Web項目構建的CRM項目如下:
原因主要是因爲上面的WEB程序要運行,我們必須將項目運行所需的Jar包複製到工程目錄中,從而導致了工程很大。
同樣的項目,如果我們使用Maven工程來構建,會發現總體上工程的大小會少很多。如下圖:
Maven的兩個比較重要的作用
1.Maven的依賴管理★
Maven的一個核心特性就是依賴管理。當我們涉及到多模塊的項目(包含成百個模塊或者子項目),管理依賴就變成一項困難的任務。Maven展示出了它對處理這種情形的高度控制。
傳統的WEB項目中,我們必須將工程所依賴的jar包複製到工程中,導致了工程的變得很大。
-
那麼maven工程是如何使得工程變得很少呢?
-
通過分析發現: maven工程中不直接將jar包導入到工程中, 而是通過在pom.xml文件中添加所需jar包的座標,這樣就很好的避免了jar直接引入進來,在需要用到jar包的時候,只要查找pom.xml文件,再通過pom.xml文件中的座標,到一個專門用於”存放jar包的倉庫”(maven倉庫) 中根據座標從而找到這些jar包,再把這些jar包拿去運行。
問題:通過讀取pom.xml 文件中的座標,再到倉庫中找到jar包,會不會很慢?從而導致這種方式不可行!
答案: 通過pom.xml文件配置要引入的jar包的座標,再讀取座標併到倉庫中加載jar包,這樣我們就可以直接使用jar包了,爲了解決這個過程中速度慢的問題,maven中也有索引的概念,通過建立索引,可以大大提高加載jar包的速度,使得我們認爲jar包基本跟放在本地的工程文件中再讀取出來的速度是一樣的。這個過程就好比我們查閱字典時,爲了能夠加快查找到內容,書前面的目錄就好比是索引,有了這個目錄我們就可以方便找到內容了,一樣的在maven倉庫中有了索引我們就可以認爲可以快速找到jar包。
2.項目的一鍵構建★
我們的項目,往往都要經歷編譯、測試、運行、打包、安裝 ,部署等一系列過程。
- 什麼是構建?
指的是項目從編譯、測試、運行、打包、安裝 ,部署整個過程都交給maven進行管理,這個過程稱爲構建。
①清理 : 刪除以前的編譯結果,爲重新編譯做好準備。
②編譯 : 將 Java 源程序編譯爲字節碼文件。
③測試 : 針對項目中的關鍵點進行測試,確保項目在迭代開發過程中關鍵點的正確性。
④報告 : 在每一次測試後以標準的格式記錄和展示測試結果。
⑤打包 : 將一個包含諸多文件的工程封裝爲一個壓縮文件用於安裝或部署。 Java 工程對應 jar 包, Web工程對應 war 包。
⑥安裝 : 在 Mav en 環境下特指將打包的結果 jar 包或 war 包安裝到本地倉庫中。
⑦部署 : 將打包的結果部署到遠程倉庫或將 war 包部署到服務器上運行。
- 一鍵構建
指的是整個構建過程,使用maven一個命令可以輕鬆完成整個工作。
Maven規範化構建流程如下:
Maven核心概念
Maven能夠 實現自動化構建 是 和它的內部原理 分不開 的, 這裏 我們 從 Maven 的九個核心概念入手
Maven 自動化構建:
- ①POM
- ②約定的目錄結構
- ③座標
- ④依賴管理
- ⑤倉庫管理
- ⑥生命週期
- ⑦插件和目標
- ⑧繼承
- ⑨聚合
★Maven構建模型
Maven包含了一個項目對象模型 (Project Object Model),一組標準集合,一個項目生命週期(Project Lifecycle),一個依賴管理系統(Dependency Management System),和用來運行定義在生命週期階段(phase)中插件(plugin)目標(goal)的邏輯。
- 項目對象模型 (Project Object Model)
一個maven工程都有一個pom.xml文件,通過pom.xml文件定義項目的座標、項目依賴、項目信息、插件目標等。
-
依賴管理系統(Dependency Management System)
-
一個項目生命週期(Project Lifecycle)
使用maven完成項目的構建,項目構建包括:清理、編譯、測試、部署等過程,maven將這些過程規範爲一個生命週期,如下所示是生命週期的各各階段:
maven通過執行一些簡單命令即可實現上邊生命週期的各各過程,比如執行mvn compile執行編譯、執行mvn clean執行清理。
- 一組標準集合
maven將整個項目管理過程定義一組標準,比如:通過maven構建工程有標準的目錄結構,有標準的生命週期階段、依賴管理有標準的座標定義等。
- 插件(plugin)目標(goal)
maven 管理項目生命週期過程都是基於插件完成的。
★Maven指令生命週期
maven對項目構建過程分爲三套相互獨立的生命週期,請注意這裏說的是“三套”,而且“相互獨立”, 這三套生命週期分別是:
- Clean Lifecycle 在進行真正的構建之前進行一些清理工作。
- Default Lifecycle 構建的核心部分,編譯,測試,打包,部署等等。
- Site Lifecycle 生成項目報告,站點,發佈站點。
插件和目標
- 生命週期的各個階段僅僅定義了要執行的任務是什麼
- 各個階段和插件的目標是對應的
- 相似的目標特定的插件來完成
- 可以將目標看作“調用插件功能的命令”
★Maven倉庫
maven的工作需要從倉庫下載一些jar包,如下圖所示,本地的項目A、項目B等都會通過maven軟件從遠程倉庫(可以理解爲互聯網上的倉庫)下載jar包並存在本地倉庫,本地倉庫 就是本地文件夾,當第二次需要此jar包時則不再從遠程倉庫下載,因爲本地倉庫已經存在了,可以將本地倉庫理解爲緩存,有了本地倉庫就不用每次從遠程倉庫下載了。
-
本地倉庫 : 用來存儲從遠程倉庫或中央倉庫下載的插件和jar包,項目使用一些插件或jar包,優先從本地倉庫查找
默認本地倉庫位置在 {user.dir}表示windows用戶目錄。 -
遠程倉庫(俗稱私服): 如果本地需要插件或者jar包,本地倉庫沒有,默認去遠程倉庫下載。
遠程倉庫可以在互聯網內也可以在局域網內。 -
中央倉庫 : 在maven軟件中內置一個遠程倉庫地址http://repo1.maven.org/maven2 ,它是中央倉庫,服務於整個互聯網,它是由Maven團隊自己維護,裏面存儲了非常全的jar包,它包含了世界上大部分流行的開源項目構件。
倉庫中保存的內容: Maven工程
1.maven自身所需要的插件
2.第三方的框架或工具的jar包
3.我們自己開發的maven工程
常見問題:
運行Maven工程時如果本地倉庫配置錯誤會報下邊的錯誤:
分析:
maven工程運行先從本地倉庫找jar包,本地倉庫沒有再從中央倉庫找,上邊提示downloading…
表示 從中央倉庫下載jar,由於本地沒有聯網,報錯。
解決:
在maven安裝目錄的conf/setting.xml文件中配置本地倉庫地址
Maven安裝與配置
百度官網打開下載:https://maven.apache.org/download.cgi
下載完後將Maven解壓到自己規定的文件夾(不要用中文名)
Maven目錄結構
bin:
存放了maven的命令,比如我們前面用到的mvn tomcat:run
boot:
存放了一些maven本身的引導程序,如類加載器等
conf:
存放了maven的一些配置文件,如setting.xml文件
lib:
存放了maven本身運行所需的一些jar包
至此我們的maven軟件就可以使用了,前提是你的電腦上之前已經安裝並配置好了JDK,運行Maven需要有JDK的支持
Maven配置
電腦上需安裝java環境,安裝JDK1.7 + 版本 (將JAVA_HOME/bin 配置環境變量path ),我們使用的是JDK8相關版本
配置 MAVEN_HOME ,變量值就是你的maven安裝 的路徑(bin目錄之前一級目錄)
再次檢查JDK的安裝目錄,如下圖:
配置好測試
cmd輸入:mvn -v
出現以下內容說明已經成功
配置本地倉庫
在MAVE_HOME/conf/settings.xml文件中配置本地倉庫位置(maven的安裝目錄下)
打開settings.xml文件,配置如下:
<localRepository>你的本地倉庫路徑</localRepository>
這是我的本地倉庫路徑,以及存放的jar包
全局setting與用戶setting
maven倉庫地址、私服等配置信息需要在setting.xml文件中配置,分爲全局配置和用戶配置。
在maven安裝目錄下的有 conf/setting.xml文件,此setting.xml文件用於maven的所有project項目,它作爲maven的全局配置。
如需要個性配置則需要在用戶配置中設置,用戶配置的setting.xml文件默認的位置在:{user.dir} 指windows 中的用戶目錄。
maven會先找用戶配置,如果找到則以用戶配置文件爲準,否則使用全局配置文件。
★Maven工程的認識
- Maven工程的目錄結構
我以IDEA普通Maven工程爲例:
IDEA中Web工程爲例
src/main/java
—— 存放項目的.java文件src/main/resources
—— 存放項目資源文件,如spring, hibernate配置文件src/test/java
—— 存放所有單元測試.java文件,如JUnit測試類src/test/resources
—— 測試資源文件target
—— 項目輸出位置,編譯後的class文件會輸出到此目錄pom.xml
——maven項目核心配置文件- 注意:如果是普通的java項目,那麼就沒有webapp目錄。
★Maven的常用命令介紹
我在cmd中通過一系列的maven命令來對我的maven工程進行編譯、測試、運行、打包、安裝、部署。
- compile
compile是maven工程的編譯命令,作用是將src/main/java下的文件編譯爲class文件輸出到target目錄下。
cmd進入命令狀態,執行mvn compile,如下圖提示成功:
發現在我的項目目錄裏多出了這個文件:
- test
test是maven工程的測試命令 mvn test
,會執行src/test/java下的單元測試類。
cmd執行mvn test執行src/test/java下單元測試類,下圖爲測試結果,運行1個測試用例,全部成功:
- clean
clean是maven工程的清理命令,執行 clean會刪除target目錄及內容。
- package
package是maven工程的打包命令,對於java工程執行package打成jar包,對於web工程打成war包。
- install
install是maven工程的安裝命令,執行install將maven打成jar包或war包發佈到本地倉庫。
★Maven座標依賴
座標使用如下三個向量在Maven 的倉庫中唯一的確定一個 Maven 工程。
- groupid:公司或組織的域名倒序 當前項目名稱
- artifactId:當前項目的模塊名稱
- version:當前模塊的版本
<!--項目名稱,定義爲組織名+項目名,類似包名-->
<groupId>cn.itcast.maven</groupId>
<!-- 模塊名稱 -->
<artifactId>maven-first</artifactId>
<!-- 當前項目版本號,snapshot爲快照版本即非正式版本,release爲正式發佈版本 -->
<version>0.0.1-SNAPSHOT</version>
<packaging >打包類型</packaging>
jar:執行package會打成jar包
war:執行package會打成war包
pom :用於maven工程的繼承,通常父工程設置爲pom
依賴小demo:
比如:項目依賴junit4.9,
通過在pom.xml
中定義junit4.9
的依賴即使用junit4.9
如下所示是junit4.9的依賴定義:
<!-- 依賴關係 -->
<dependencies>
<!-- 此項目運行使用junit,所以此項目依賴junit -->
<dependency>
<!-- junit的項目名稱 -->
<groupId>junit</groupId>
<!-- junit的模塊名稱 -->
<artifactId>junit</artifactId>
<!-- junit版本 -->
<version>4.9</version>
<!-- 依賴範圍:單元測試時使用junit -->
<scope>test</scope>
</dependency>
</dependencies>
★依賴範圍
A依賴B,需要在A的pom.xml
文件中添加B的座標,添加座標時需要指定依賴範圍,依賴範圍包括:
compile:
編譯範圍,指A在編譯時依賴B,此範圍爲默認依賴範圍。編譯範圍的依賴會用在編譯、測試、運行,由於運行時需要所以編譯範圍的依賴會被打z包。provided:
provided依賴只有在當JDK或者一個容器已提供該依賴之後才使用, provided依賴在編譯和測試時需要,在運行時不需要,比如:servlet api被tomcat容器提供。runtime:
runtime依賴在運行和測試系統的時候需要,但在編譯的時候不需要。比如:jdbc的驅動包。由於運行時需要所以runtime範圍的依賴會被打包。test:
test範圍依賴 在編譯和運行時都不需要,它們只有在測試編譯和測試運行階段可用,比如:junit。由於運行時不需要所以test範圍依賴不會被打包。system:
system範圍依賴與provided類似,但是你必須顯式的提供一個對於本地系統中JAR文件的路徑,需要指定systemPath磁盤路徑,system依賴不推薦使用。
在maven-web工程中測試各各scop。
測試總結:
- 默認引入 的jar包 ------- compile 【默認範圍 可以不寫】(編譯、測試、運行 都有效 )
- servlet-api 、jsp-api ------- provided (編譯、測試 有效, 運行時無效 防止和tomcat下jar衝突)
- jdbc驅動jar包 ---- runtime (測試、運行 有效 )
- junit ----- test (測試有效)
- 依賴範圍由強到弱的順序是:compile>provided>runtime>test
pom.xml基本配置
pom.xml是Maven項目的核心配置文件,位於每個工程的根目錄,基本配置如下:
文件的根節點
<project>
<artifactId> 模塊名稱,子項目名或模塊名稱就是Idea中的Module</artifactId>
<!--pom.xml使用的對象模型版本-->
<modelVersion>4.0.0</modelVersion>
<!--項目依賴構件配置,配置項目依賴構件的座標-->
<dependencies>
<dependency>
<groupId>項目名稱,一般寫項目的域名</groupId>
<artifactId>模塊名稱,子項目名或模塊名稱</artifactId>
<version>產品的版本號</version>
<scope>依賴範圍</scope>
</dependency>
</dependencies>
<build> 項目構建配置,配置編譯、運行插件等。</build>
<name > 項目的顯示名,常用於 Maven 生成的文檔。</name>
<description>項目描述,常用於 Maven 生成的文檔</description>
</project>
依賴的傳遞性
假如:在你的Maven項目裏定義了3個Maven工程
HelloFriend工程與工程2,和工程3
依賴關係:HelloFriend→工程2→工程3
我在HelloFriend這個最底層的工程添加了Spring-core依賴,那麼在工程2和工程3中都有Spring-core的依賴,這個就是依賴的傳遞性
但是: 非compile範圍的依賴不能傳遞,所以在各個工程的模塊中,如果由需要,就得重複聲明依賴。
依賴的排除
排除依賴的方式:
<exclusions>
<exclusion>
<groupId>commos-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
依賴的原則:
統一管理依賴的版本
繼承
問題出現:
- 工程1依賴的Junit:4.0
- 工程2依賴的Junit:4.0
- 工程3依賴的Junit:4.9
由於依賴範圍中的test
不能傳遞,所以在各個模塊的工程中,容易造成版本不一致
那麼如何解決問題:讓各個版本統一。
答案:將junit依賴統一到“父”工程中,在子工程中聲明junit依賴時不指定版本
聚合
將多個工程拆分爲模塊後, 需要 手動逐個 安裝 到倉庫後 依賴 才能夠生效。 修改 源碼後 也 需要 逐個 手動進行 clean 操作。 而 使用了聚合之後就可以批量進行 Maven 工程的安裝、清理工作。
在總的聚合工程中 使用 modules /module 標籤 組合, 指定 模塊工程的 相對 路徑即 可
<modules>
<module>../Hello</module>
<module>../HelloFriend</module>
<module>../MakeFriends</module>
</modules>
最後:
以上皆是本人在學習Maven中的所有筆記,整理不易!希望有所幫助!
如果有任何問題可以私信我。