場景 : 最近使用springboot寫一些小demo,發現到處都要使用maven,更離不開其中的pom.xml文件,所以這里對maven的常規使用作出一個整理。
轉載自 : 本文很多內容都是仿照 http://www.cnblogs.com/qbzf-Blog/p/6539161.html 來的。而且他還提供了一個慕課網的學習視頻:http://www.imooc.com/learn/443。
文章結構 :
1. 安裝配置maven環境
2. maven目錄結構
3. HelloMaven
4. 常用構建命令
5. 使用archetype插件自動建立目錄
6. 坐標&倉庫
7. 生命周期&插件的使用
8. pom.xml常用標簽介紹
9. maven依賴(范圍、傳遞、沖突)
10. 聚合&繼承
正文 :
1. 安裝配置maven環境
首先,在官網中下載maven組件。進入官網后,在左邊菜單找到Download選項,點擊進入Download頁面。
當然,我們首先要保證JDK安裝好。接下來,要在本地配置好maven的系統環境變量,
新建一個maven_home的變量,然后在系統變量的path后面追加這個maven_home;
接着,我們測試下maven安裝成功沒有(注意,一般我們都先安裝好JDK,因為maven的命令應該是要借助jdk的):
如圖所示,顯示了maven的版本信息跟jdk的版本信息,當然,我們也可以使用echo 查看下 系統環境變量 :
到這里,我們對maven的環境配置就完成了。其實這是第一種,我們下載jar包的形式,不過本人是使用第二種,直接安裝eclipse(包含maven)的版本即可,
比如我安裝的版本即是自帶的maven;接下來只需要配置好本地的系統變量即可。
誒,如果我們想要改變maven的版本呢,我們可以在eclipse當中的preferences當中改變:
2. maven項目的目錄結構
先在這里插入一點個人對maven的理解,我們之前每個項目都需要有自己的jar包,但是這么多jar包很多有相同的,而這些jar包又是基於項目存放的,如果我們跨越項目這一層,統一管理jar包呢, 這樣不就可以節約很多空間和時間。所以,我們使用maven工具來支配之,那么我們maven存放jar包的地方就是我們說的倉庫,
當我們在第一步設置好maven的環境之后,默認就在c盤的user目錄下的.m2文件夾充當倉庫。
a
maven在每台機器上創建一個本機倉庫,把本機上所有maven項目依賴的jar包統一管理起來,而且這些jar包用“坐標”來唯一標識(注:坐標是另一個重要的概念,后面還會講到,這里只要簡單理解成“唯一識別某個jar包文件名、版本號”的標識即可),這樣所有maven項目就不需要再象以前那樣把jar包復制到lib目錄中,整個maven項目看起來十分清爽。
扯了很多,現在說下maven項目的目錄結構是怎樣的 :
誒,這些有些怎么標紅呢? 是因為我們使用maven約定由於配置。src/main/java約定用於存放源代碼,src/main/test用於存放單元測試代碼,src/target用於存放編譯、打包后的輸出文件。這是全世界maven項目的通用約定,請記住這些固定的目錄結構。
3. 構建一個HelloMaven項目
上面介紹完了我們該使用怎樣的約定來開發一個項目,接下來我們創建一個項目。
new一個maven項目,寫好坐標(待會介紹)。這里說的坐標就是上面的groupid以及artifact id。創建好之后的結構如下圖所示:
接下來我們嘗試編譯下這個項目,命令行進入項目路徑,使用mvn compile命令(當然,直接在eclipse上run as這個項目使用maven的幾個選項都是可以的)。編譯之后會生成target目錄,里面存放的是class文件 :
我們接下來編譯下 :
我們查看下項目目錄 :
我們這里在maven項目的測試類中寫個syso輸出 :
OK,我們再在控制台輸入mvn clean ,清理下class文件,再輸入mvn compile 再次編譯一下,接着輸入mvn test執行AppTest.class文件:
我們可以看到已經輸出成功了。
4. 常用構建命令
從第3步驟可以看出,這些命令的使用了,其實很像使用java命令編譯對不對。那么我們來介紹下maven的這些構建命令 : 其形式一般都是在命令行 mvn xxx的這種格式 :
mvn {
-v 查看maven版本以及其他相關信息
compile 編譯maven項目,並生成target文件夾
test 運行test目錄下的測試文件,即測試
package 將項目打包,默認打包為jar格式,也可以打包成war格式用於服務器運行
install 將打包的jar文件安裝到maven本地倉庫
clean 刪除target,相當於清除緩存
}
這些命令在集成了maven的eclipse當中也有對應選項可以操作 :
我們可以右鍵一個項目,然后run as 就會出現這些選項,在下面的maven當中 還有update選項;
那這么多命令,我們怎么知道怎么合理使用呢,其實我們只需要理解到整個項目的構建過程就可以明白這一點了:
項目構建過程包括【清理項目】→【編譯項目】→【測試項目】→【生成測試報告】→【打包項目】→【部署項目】這幾個步驟,這六個步驟就是一個項目的完整構建過程。(mvn clean -> mvn compile -> mvn test -> mvn package)
而上面所說的maven update是針對我們在項目中的pom.xml當中引入了新的jar包之后,需要重新update一下,此處的應用場景就是 :
比如我們A項目在pom.xml引入了一個新包,這個時候我們需要把A項目重新update一下才能使用新jar包當中的東西(不過很多時候我們項目有自動重構);如果這個時候我們B項目引用了A,也想使用這個新jar包,我們也應當update一下,避免發生引用錯誤,還有一個常見的使用場景就是我們import一個新的maven聚合項目的時候,需要clean install :
然后我們還要update把jar包下下來,這個時候如果依賴包過多,其下載是相當大的,所以我們可以指定maven倉庫的位置為阿里的(更改setting文件后面作出介紹。)
下面我列舉一下常用的maven 命令(注意我上面在eclipse當中不是maven clean 而是clean,原因嗎我也不知道啦):
- 創建一個簡單的Java工程:mvn archetype:create -DgroupId=com.mycompany.example -DartifactId=Example
- 創 建一個java的web工程:mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp
- 打包:mvn package
- 編譯:mvn compile
- 編譯測試程序:mvn test-compile
- 清空:mvn clean
- 運行測試:mvn test
- 生成站點目錄: mvn site
- 生成站點目錄並發布:mvn site-deploy
- 安裝當前工程的輸出文件到本地倉庫: mvn install
- 安 裝指定文件到本地倉庫:mvn install:install-file -DgroupId=<groupId> -DartifactId=<artifactId> -Dversion=1.0.0 -Dpackaging=jar -Dfile=<myfile.jar>
- 查看實際pom信息: mvn help:effective-pom
- 分析項目的依賴信息:mvn dependency:analyze 或 mvn dependency:tree
- 跳過測試運行maven任務: mvn -Dmaven.test.skip=true XXX
- 生成eclipse項目文件: mvn eclipse:eclipse (將maven項目轉換成eclipse項目)
- 查看幫助信息:mvn help:help 或 mvn help:help -Ddetail=true
- 查看插件的幫助信息:mvn <plug-in>:help,比如:mvn dependency:help 或 mvn ant:help 等等。
這里我還想多說一點,其實maven的功能不僅僅是這樣,如下我列舉一些maven的常用基本功能 :
(轉載自 https://www.cnblogs.com/adolfmc/archive/2012/07/31/2616908.html)
- 構建:比如生成class、jar、war或者ear文件
- 生成文檔:比如生成javadoc、網站文檔
- 生成報告:比如junit測試報告
- 生成依賴類庫:生成文檔,說明項目多其他軟件的依賴
- 有關SCM:SCM(Software Configuration Management),軟件配置管理,比如版本控制,比如bug管理等等
- 發布:生成供發布的分發包,比如生成Struts2的分發包,供提交給用戶使用
- 部署:比如,web應用程序,自動部署到指定的服務器上
-
Maven資源
-
見官方網站;
-
The 5 minute test,官方簡易入門文檔;
-
Getting Started Tutorial,官方入門文檔;
-
Build Cookbook,官方的cookbook;
-
POM Reference,POM文件的設置參考
-
Settings Reference ,settings文件的設置參考
-
Better Builds with Maven,免費的電子書,下載需要注冊。
-
5.使用archetype插件自動建立目錄
這個本人不作出介紹了,哈哈,沒用過。
6. 坐標和倉庫
坐標 :
maven使用groupId、artifactId、version表示坐標,每個坐標都唯一的指向一個maven項目,簡單介紹一下這幾個標簽
groupId:項目組織唯一的標識符,一般為反寫的公司網址+項目名
artifactId:項目的唯一的標識符,一般為項目名+模塊名
version:版本號 x.x.x+版本類型
第一個x表示大版本號
第二個x表示分支版本號
第三個x表示小版本號(可省略)
常見版本類型:
snapshot快照
alpha內部測試
beta公測
release穩定
GA正式發布
注:包名應與groupId+artifactId相吻合。
倉庫 : maven的依賴管理是靠着倉庫來支撐的,倉庫分為中央倉庫和本地倉庫。在編譯項目時,maven會根據配置的依賴,現在本地倉庫中進行搜索,若是沒有則再去倉庫進行搜索,而搜索便是采用坐標進行查找。倉庫默認為本地的c盤users文件夾下面的.m2的repository。如果不想放在C盤的話,可以對maven進行配置:
如圖,可以自己重寫localRepository;
7. 生命周期 & 插件的使用
多個生命周期之間相互獨立。每個生命周期含有多個階段,階段按順序執行,運行后階段時,前階段會自動執行。比如,直接運行mvn test命令,那么執行該命令時,會自動的附帶mvn compile命令,因為test階段在compile階段之后。
上面我們就說過,一個完整的項目的構建過程包括 :
清理、編譯、測試、打包、集成測試、驗證、部署;
clean 清理項目,包括以下階段:
pre-clean 執行清理前
clean 清理上一次構建生成的所有文件
post-clean 執行清理后的文件
default 構建項目(核心:常用),包括以下階段
compile 編譯
test 測試
packeage 打包
install 安裝
site 生成項目站點,根據pom中信息生成項目站點,包括以下階段
pre-site 在生成項目站點前要完成的工作
site生成項目的站點文檔
post-site在生成項目站點后要完成的工作
site-deploy發布生成的站點到服務器上
插件:
maven中提供了許多功能強大的插件,讓我們更好的管理項目。一個插件通常提供了一組目標,可使用以下語法來執行:
mvn [plugin-name]:[goal-name]
例如我們之前使用mvn archetype:generate,插件名為archetype,而目標為generate。我們可以在官網的Plugins標簽下,查找到插件的坐標及插件目標的詳細描述。
Maven 提供以下兩種類型插件:
類型 | 描述 |
---|---|
構建插件 | 在生成過程中執行,並在 pom.xml 中的<build/> 元素進行配置 |
報告插件 | 在網站生成期間執行,在 pom.xml 中的 <reporting/> 元素進行配置 |
以下是一些常見的插件列表:
插件 | 描述 |
---|---|
clean | 編譯后的清理目標,刪除目標目錄 |
compiler | 編譯 Java 源文件 |
surefile | 運行JUnit單元測試,創建測試報告 |
jar | 從當前項目構建 JAR 文件 |
war | 從當前項目構建 WAR 文件 |
javadoc | 產生用於該項目的 Javadoc |
antrun | 從構建所述的任何階段運行一組 Ant 任務 |
source | 從當前項目構建帶源碼的JAR文件 |
比如我們拿source來測試:
<build>
<!-- 配置插件集 -->
<plugins>
<plugin>
<!--使用插件的坐標進行引用 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<!-- 綁定在哪個過程時一同執行,這里我們讓它在使用package打包時一同執行 -->
<phase>package</phase>
<!--執行的目標類型,關於目標的詳細介紹可以在maven官網中查到-->
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
我們接下來先編譯一下 :
然后,我們在來看使用打包命令之后會不會生成源jar包。
我們可以看到在下載很多東西了 ,接下來看下文件夾生成了源jar包沒 :
從這里我們可看成,這里有幾個關鍵點,在pom.xml當中使用plugin來申明要使用的插件,然后還可以綁定到某個過程中執行,我們這里就綁定到了package當中執行。
8. 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">
<!-- 當前pom的版本-->
<modelVersion>4.0.0</modelVersion>
<!--坐標-->
<groupId>cn.edu</groupId>
<artifactId>maven04</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 默認是jar,其他war zip pom等 -->
<packaging>jar</packaging>
<!--項目描述名 -->
<name>maven04</name>
<!-- 項目地址 -->
<url>http://maven.apache.org</url>
<!-- 配置參數 -->
<properties>
<!-- 這里配置項目編譯編碼為UTF-8-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 開發人員信息 -->
<developers></developers>
<!-- 項目描述 -->
<description></description>
<!-- 許可信息 -->
<licenses></licenses>
<!-- 組織信息 -->
<organization></organization>
<!-- 依賴集,用於配置依賴 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<!-- 依賴范圍:這個jar包只在范圍內生效,范圍外引用會報錯,這里讓junit只在test時被依賴。
其他一些情況,如:servlet-api.jar,在編譯階段需要引用,而在服務器運行階段則不需要引用,就可以使用scope-->
<scope>test</scope>
<!-- 默認為false,子項目將會繼承,true時子項目並需顯式引用 -->
<optional>false</optional>
<!-- 排除依賴列表:用於去除傳遞依賴等,在后面會詳細介紹-->
<exclusions>
<exclusion></exclusion>
</exclusions>
</dependency>
</dependencies>
<!-- 依賴管理
為依賴進行統一管理,如果在父項目中聲明此標簽時,在子項目中不需聲明,確保父子項目依賴版本一致;
如子項目需要不同版本的依賴,只需在子項目中進行聲明即可,將會覆蓋父項目中的聲明。
-->
<!--
<dependencyManagement>
<dependencies>
<dependency></dependency>
</dependencies>
</dependencyManagement>
-->
<!--配置構建時的屬性-->
<build>
<plugins></plugins>
</build>
<!-- 指定父模塊 -->
<!-- <parent></parent> -->
<!-- 用於聚合編譯多個maven模塊 -->
<modules></modules>
</project>
9. maven依賴 (范圍、傳遞、沖突)
范圍:
首先要知道,maven中提供了三種classpath:編譯、測試、運行
scope標簽
-compile 默認,編譯測試運行均有效,會傳遞
-provided 在編譯和測試時有效,如servletAPI可以加入,不傳遞
-runtime 在測試和運行時有效,如JDBCAPI可以加入
-test 在測試時有效,如junit可以加入
-system 在編譯和測試時有效,與本機系統相關聯,移植性差,在系統中以外部jar包的形式引入,不會在倉庫中查找
-import 導入,只能用在dependecyManagement中,表示從其他pom中導入dependecy的配置
傳遞:
先來看看什么是傳遞依賴,比如現在有這么個情況:
C依賴B、B依賴A——C→B→A,那么此時C也會依賴A且會包含A中的依賴,這就是傳遞依賴。接下來我們通過一個例子來詳細了解依賴及如何消除傳遞依賴:
現有ABC三個項目:
A中額外依賴了一個commons-io的jar包:
B中對A進行依賴:
C中對B進行依賴:
保存之后可以看到,C中不但包含B,還包含A和A依賴的common-io:
那么如何消除傳遞依賴呢,這里就使用到<exclusion>標簽了,在C中配置依賴B的地方加入以下內容:
保存后就可以看到,C中關於A的依賴消失了,傳遞依賴的問題就解決了。
沖突:
假設現在有這么個情況:A依賴common-io的2.4版本,B依賴common-io的2.5版本,C依賴A、B,那么此時C中的common-io是哪個版本的?
這就是依賴沖突,在maven中應對依賴沖突有兩種解決方式:短路優先,先聲明優先
先聲明優先:顧名思義,在pom中,寫在配置文件上面的優先,比如此時A的依賴配置在B之上,那C中就為2.4版本的common-io。
短路優先:優先選擇依賴路徑較短的一端。假設現在多出一個D,依賴情況改為D依賴B,C依賴A、D——C→A、C→D→B,那么這里就是A的依賴路徑比較短,所以為2.4版本。
10. 聚合&繼承
聚合:
試想一下這樣的情況,在一個項目中,分模塊使用了maven,那么可能在這個項目中會有五六個,或者更多的maven項目存在。如果此時需要編譯或測試要怎么辦呢,進入每個maven項目中進行mvn compile么,那就要執行五六次的compile命令,十分繁瑣,這里就可以用maven的聚合來解決這個問題。
現有ABC三個工程,那么我們使用一個新的工程D,來聚合他們,以后只要對D進行編譯即可對三個工程同時進行編譯。使用module標簽進行聚合:
<modules> <!--這里的路徑是基於D項目的pom.xml路徑,module標簽內為指向其他項目的pom文件的路徑 這里我的ABCD項目在同一個文件夾內,那么從D內的pom中,通過../項目名,來找到其他項目的pom.xml--> <module>../A</module> <module>../B</module> <module>../C</module> </modules>
繼承:
另一種情形,如果多個maven項目具有相同的依賴時或配置時,那么應該如何處理呢?這里就用到繼承的概念,在maven中使用<parent>標簽來進行繼承,下面通過一個例子來看一下:
首先建立一個項目,命名為parent,在parent的pom文件聲明一個common-io的依賴,不過這里用到了dependencyManagement:
<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>cn.edu</groupId> <artifactId>parent</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <name>parent</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.12</version> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <!-- 在這里聲明的依賴可以被子項目繼承引用 --> <dependencies> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> </dependencies> </dependencyManagement> </project>
可以看到,雖然我們在父項目中配置了依賴,但是卻不會在父項目中被引用:
在子項目B中,配置繼承parent並使用parent中的common-io版本:
<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>cn.edu</groupId> <artifactId>B</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>B</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <!-- 在parent標簽中使用父項目的坐標進行配置 --> <parent> <groupId>cn.edu</groupId> <artifactId>parent</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <dependencies> <!-- 此處使用依賴時,就不需聲明版本 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
配置后保存即可看到,此處的依賴版本即為父項目中的版本: