一. 什么是maven
基于java的一款跨平臺的項目構建、依賴管理秦士、項目信息管理的工具销斟。
二.maven安裝和配置
2.1 windows安裝maven
1.檢查jdk是否安裝 java -version
2.下載解壓maven
https://maven.apache.org/download.cgi
下載后解壓到指定目錄(如:D:\java\apache-maven-3.5.0)
設置環(huán)境變量:
在系統變量中添加變量名為 MAVEN_HOME祭玉,內容是解壓的maven文件路徑箱熬。
然后在Path中添加 %MAVEN_HOME%\bin
然后運行mvn -v 驗證是否安裝成功
2.2 在unix系統上安裝Maven
首先下載Maven并解壓,并移動到usr/local目錄下
$ wget http://[mirror.bit.edu.cn/apache](http://mirror.bit.edu.cn/apache)/maven/maven-3/3.2.3/binaries/apache-maven-3.2.3-bin.tar.gz
$ tar vxf apache-maven-3.2.3-bin.tar.gz
$ mv apache-maven-3.2.3 /usr/local/maven3
修改環(huán)境變量窄俏,在/etc/profile中添加以下幾行
MAVEN_HOME=/usr/local/maven3
export MAVEN_HOME
export PATH=${PATH}:${MAVEN_HOME}/bin
記得執(zhí)行source /etc/profile
使環(huán)境變量生效蹂匹。
最后運行mvn -v
驗證maven是否安裝成功,如果安裝成功會打印如下內容
Apache Maven 3.2.3 (33f8c3e1027c3ddde99d3cdebad2656a31e8fdf4; 2014-08-12T04:58:10+08:00)
Maven home: /usr/local/maven3
Java version: 1.7.0_65, vendor: [Oracle](https://www.linuxidc.com/topicnews.aspx?tid=12 "Oracle") Corporation
Java home: /usr/lib/jvm/java-7-openjdk-amd64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.13.0-35-generic", arch: "amd64", family: "unix"
2.3 ~./m2 和 setting.xml
在我們在安裝好maven后凹蜈,在用戶目錄下會發(fā)現.m2文件夾限寞, 也是本地倉庫的位置(idea 有時加了 -U參數,倉庫里是拉下來了最新的SNAPSHOT仰坦,但是idea里拿不到最新的代碼履植,可以到本地倉庫中刪除后重新拉取就可以了)
setting.xml的配置在 默認的模板上修改配置即可。
安裝maven后悄晃,在maven安裝目錄的conf文件下會有setting.xml文件玫霎,但是一般需要復制setting.xml文件到~/.m2/setting.xml(最佳實踐)
默認M2_HOME/conf/setting.xml是全局配置,對于登錄不同用戶都將都受到影響妈橄,而在~/.m2/setting.xml指影響登錄用戶庶近,同時便于升級maven。
三.maven依賴
3.1maven pom文件的結構
maven的整個構建都是基于pom.xml
<?xml version=``"1.0"` `encoding=``"UTF-8"``?>
<project xmlns=``"[http://maven.apache.org/POM/4.0.0](http://maven.apache.org/POM/4.0.0)"
xmlns:xsi=``"[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)"
xsi:schemaLocation=``"[http://maven.apache.org/POM/4.0.0](http://maven.apache.org/POM/4.0.0) [http://maven.apache.org/xsd/maven-4.0.0.xsd](http://maven.apache.org/xsd/maven-4.0.0.xsd)"``>
<!--聲明項目描述符遵循哪一個POM模型版本眷蚓。模型本身的版本很少改變拦盹,雖然如此,但它仍然是必不可少的溪椎,這是為了當Maven引入了新的特性或者其他模型變更的時候,確保穩(wěn)定性恬口。-->
<modelVersion>``4.0``.``0``</modelVersion>
<!--項目的全球唯一標識符校读,通常使用全限定的域名區(qū)分該項目和其他項目。并且構建時生成的路徑也是由此生成祖能, 如com.mycompany.app生成的相對路徑為:/com/mycompany/app-->
<groupId>com.miui.media.auto</groupId>
<!-- 構件的標識符歉秫,它和group ID一起唯一標識一個構件,項目下的某個模塊 -->
<artifactId>auto-maven</artifactId>
<!--項目產生的構件類型,例如jar养铸、war雁芙、pom。插件可以創(chuàng)建他們自己的構件類型钞螟,所以前面列的不是全部構件類型-->
<packaging>pom</packaging>
<!--項目版本-->
<version>``1.0``-SNAPSHOT</version>
<!--項目的名稱, Maven產生的文檔用-->
<name>auto-maven</name>`
<!--模塊(有時稱作子項目) 被構建成項目的一部分兔甘。列出的每個模塊元素是指向該模塊的目錄的相對路徑-->
<modules>
<module>auto-maven-base</module>
</modules>
<!--項目描述-->
<description>maven 例子</description>
<!--父項目的坐標。如果項目中沒有規(guī)定某個元素的值鳞滨,那么父項目中的對應值即為項目的默認值洞焙。 坐標包括group ID,artifact ID和 version。-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<!-- 父項目的pom.xml文件的相對路徑澡匪。相對路徑允許你選擇一個不同的路徑熔任。默認值是../pom.xml。Maven首先在構建當前項目的地方尋找父項 目的pom唁情,其次在文件系統的這個位置(relativePath位置)疑苔,然后在本地倉庫,最后在遠程倉庫尋找父項目的pom甸鸟。-->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--項目屬性-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 繼承自該項目的所有子項目的默認依賴信息惦费。這部分的依賴信息不會被立即解析,而是當子項目聲明一個依賴(必須描述group ID和 artifact ID信息),如果group ID和artifact ID以外的一些信息沒有描述哀墓,則通過group ID和artifact ID 匹配到這里的依賴趁餐,并使用這里的依賴信息。-->
<dependencyManagement>
<dependencies>
</dependencies>
</dependencyManagement>
<!--在列的項目構建profile篮绰,如果被激活后雷,會修改構建處理-->
<profiles>
</profiles>
<!--構建項目需要的信息-->
<build>
<!--子項目可以引用的默認插件信息。該插件配置項直到被引用時才會被解析或綁定到生命周期 -->
<pluginManagement>
</pluginManagement>
<!--使用的插件列表 吠各。-->
<plugins>
</plugins>
</build>
<!--項目分發(fā)信息臀突,在執(zhí)行mvn deploy后表示要發(fā)布的位置。有了這些信息就可以把網站部署到遠程服務器或者把構件部署到遠程倉庫贾漏。-->
<distributionManagement>
<repository>
<id>archiva.internal</id>
<name>Internal Release Repository</name>
<url>http:``//nexus.d.xiaomi.net/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>archiva.snapshots</id>
<name>Internal Snapshot Repository</name>
<url>http:``//nexus.d.xiaomi.net/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
3.2坐標和依賴
maven坐標:
groupId, artifactId, version蔓纠,packaging祟剔,classifier。這些組合的標識符拼成了一個項目的坐標,就像任何其它的坐標系統焕襟,一個Maven坐標是一個地址,即“空間”里的某個點:從一般到特殊蛀缝。當一個項目通過依賴萤厅,插件或者父項目引用和另外一個項目關聯的時候,Maven通過坐標來精確定位一個項目蜜笤。Maven坐標通常用冒號來作為分隔符來書寫濒蒋,像這樣的格式:groupId:artifactId:packaging:version
**groupId **
d 團體,公司把兔,小組沪伙,組織,項目县好,或者其它團體围橡。團體標識的約定是,它以創(chuàng)建這個項目的組織名稱的逆向域名(reverse domain name)開頭聘惦。來自Sonatype的項目有一個以com.sonatype開頭的groupId某饰,而Apache Software的項目有以org.apache開頭的groupId儒恋。
**artifactId **
在groupId下的表示一個單獨項目的唯一標識符。
**version **
一個項目的特定版本黔漂。發(fā)布的項目有一個固定的版本標識來指向該項目的某一個特定的版本诫尽。而正在開發(fā)中的項目可以用一個特殊的標識,這種標識給版本加上一個“SNAPSHOT”的標記炬守。
項目的打包格式也是Maven坐標的重要組成部分牧嫉,但是它不是項目唯一標識符的一個部分。一個項目的groupId:artifactId:version使之成為一個獨一無二的項目减途;你不能同時有一個擁有同樣的groupId, artifactId和version標識的項目酣藻。
**packaging **
項目的類型,默認是jar鳍置,描述了項目打包后的輸出辽剧。類型為jar的項目產生一個JAR文件,類型為war的項目產生一個web應用
**classifier **
該元素用來幫助定義一些構建項目輸出的一些附屬構建税产,如javadoc.jar或者sources.jar等
項目構件的文件名域坐標相對應怕轿,一般的規(guī)則為artifactId-version[-classifier].packaging
依賴配置:
groupId、artifactId辟拷、version為對應的坐標
type:依賴的類型撞羽,對應于packaging,默認為jar
scop:依賴范圍
用來控制依賴在測試衫冻、編譯和運行時classpath中應該依賴哪些包诀紊,maven有以下幾種依賴范圍
1. compile 默認的范圍,編譯測試運行都有效隅俘。 (spring-core)
2. provided 編譯和測試時有效邻奠,最后是在運行的時候不會被加入。比如在JavaEE web項目中我們需要使用servlet的API为居,但是呢Tomcat中已經提供這個jar惕澎,我們在編譯和測試的時候需要使用這個api,但是部署到tomcat的時候颜骤,如果還加入servlet構建就會產生沖突,這個時候就可以使用provided捣卤。
3. runtime 在測試和運行時有效忍抽。 (jdbc驅動包mysql-connector-java )
4. test 在測試時有效。 (junit)
5. system 與本機系統相關聯董朝,可移植性差鸠项。編譯和測試時有效。 使用時必須通過systemPath來顯示指定文件路徑
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency
6. import 導入的范圍子姜,它只在使用dependencyManagement中祟绊,表示從其他pom中導入dependecy的配置。
optional:標記依賴是否可選 A→B, B->X(optional),B→Y (optional) 這時X和Y不會傳遞過來 如果A要用有關X和Y的功能,得獨立依賴進來牧抽。
exclusions:排除傳遞性依賴 (commons-logging silf4j會找不到日志入口)
3.3 傳遞性依賴
舉例:
我們的項目依賴于server嘉熊,apus-server也有他自己的依賴(下圖左),當我們的項目依賴了server扬舒,apus的依賴也會對應的傳遞過來(下圖右)
A→B, B->C,B→D C和D會傳遞到A的依賴集里面(前提是C和D沒有被裁剪掉)
3.4 依賴范圍對依賴傳遞的影響
假設A依賴于B阐肤,B依賴于C,我們定A對于B是第一直接依賴讲坎,B對于C是第二直接依賴孕惜,A對于C是傳遞性依賴,下圖左一列代表第一直接依賴范圍晨炕,最上面一行代表
第二直接依賴范圍衫画,中間的相交內容代表傳遞性依賴范圍
3.5 依賴調解
因為依賴具有傳遞性,假如對于A同時直接依賴了B和C瓮栗,B依賴于D的1.0.0版本削罩,C依賴于D的2.0.0版本(無論是直接依賴還是間接依賴),如果兩個版本都依賴都定會報錯遵馆,造成重復依賴
這時A對于D的傳遞性依賴到底是1.0.0還是2.0.0鲸郊?
依賴調解原則一:路徑近者優(yōu)先
A->B->C→X(2.0) 路徑為3
A->D→X(1.0) 路徑為2
這時A→X(1.0)
那對于A->B→Y(1.0), A->D->Y(2.0)呢?
依賴調解原則二:先聲明者優(yōu)先 (v2.0.9開始)
如果在denpendencies中先聲明了B則依賴于Y(1.0),反之依賴于Y(2.0)
3.6優(yōu)化依賴
maven三劍客:
dependency:list 獲取解析后的依賴(并列顯示货邓,分不清是怎么依賴進來的)如下
[圖片上傳失敗...(image-67ec4f-1606528449098)]
dependency:tree (可以清晰的看到依賴樹秆撮,某個依賴是通過怎樣的路徑傳遞進來)
[圖片上傳失敗...(image-f712cc-1606528449098)]
如果加-Dverbose可以看到所有的依賴傳遞,和maven是怎么依賴調解的
[圖片上傳失敗...(image-4017dc-1606528449098)]
當然還可以加一些類似搜索的參數Dincludes或者Dexcludes换况,來滿足查找需求
dependency:analyze
[圖片上傳失敗...(image-33e1c8-1606528449098)]
我們看到結果是有2部分組成职辨, Used undeclared dependencies found:是指我們沒有在項目中顯示的聲明依賴,但是我們在項目中在使用戈二,
這種就會存在一些潛在的風險舒裤,如上圖中的org.apache.thrift:thrift:jar:0.5.0-mdf2.0.0:compile,我們在可能在新依賴的包的時候會覆蓋掉觉吭,但是
新的版本里沒有原來版本的接口腾供,可能會出錯,對于這類我們可以顯示的聲明依賴
另一部分是 Unused declared dependencies found: 顯示聲明但是未使用鲜滩,不能一股腦直接刪除(analyze只會分析編譯主代碼和測試代碼需要的依賴)伴鳖,
可能在運行的時候需要這些包
可以用插件來聲明白名單:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<ignoredUsedUndeclaredDependencies>
<ignoredUsedUndeclaredDependency>org.springframework:spring-beans</ignoredUsedUndeclaredDependency>
<ignoredUsedUndeclaredDependency>org.springframework:spring-context-support</ignoredUsedUndeclaredDependency>
</ignoredUsedUndeclaredDependencies>
<ignoredUnusedDeclaredDependencies>
<ignoredUnusedDeclaredDependency>com.meituan.service.mobile:mtthrift</ignoredUnusedDeclaredDependency>
</ignoredUnusedDeclaredDependencies>
</configuration>
</plugin>
四. maven倉庫
4.1maven倉庫的布局
groupId/artifactId/version/artifactId-version.packaging
4.2maven倉庫分類
本地倉庫一般在~./m2/repository 也可以在setting文件中用localRepository顯示的指定
1.私服:
私服的優(yōu)點:
節(jié)省外網的帶寬,加速maven的構建徙硅,部署第三方構件榜聂,提高穩(wěn)定性,增強控制(權限管理)嗓蘑,降低中央倉庫的負荷
2.遠程倉庫的配置
`<repositories>`
`<repository>`
`<id>central</id>`
`<url>http:``//nexus</url>`
`<releases>`
`<enabled>``true``</enabled>`
`<updatePolicy>daily</updatePolicy>`
`<checksumPolicy></checksumPolicy>`
`</releases>`
`<snapshots>`
`<enabled>``true``</enabled>`
`</snapshots>`
`</repository>`
`</repositories>`
其中releases和snapshots中的enabl可以配置true和false代表是否支持下載须肆,updatePolicy更新頻率
默認daily每天更新一次匿乃,never從不更新,always每次構建都更新豌汇,interval:X 每隔X分鐘更新一次
<pre style="margin: 10px 0px 0px; padding: 0px; font-family: ConfluenceInstalledFont, monospace;">checksumPolicy校驗策略默認為warn幢炸, 還有ignore和fail</pre>
注意:maven自帶的遠程倉庫id為central,如果在配置遠程倉庫使用了這個id,就會覆蓋中央倉庫的配置
3.遠程倉庫認證
`<servers>`
`<server>`
`<id>deploy</id>`
`<username>admin</username>`
`<password>admin123</password>`
`</server>`
`<server>`
`<id>archiva.internal</id>`
`<username>renfeiwei</username>`
`<password>***</password>`
`</server>`
`<server>`
`<id>archiva.snapshots</id>`
`<username>renfeiwei</username>`
`<password>***</password>`
`</server>`
`</servers>`
必須配置在setting中瘤礁,不能配置在pom中阳懂,id需要和pom中的distributionManagement 中respository對應上
4.部署項目到遠程倉庫 deploy
pom中配置
`<distributionManagement>`
`<repository>`
`<id>archiva.internal</id>`
`<name>Internal Release Repository</name>`
`<url>http:``//nexus.d.xiaomi.net/nexus/content/repositories/releases/`
`</url>`
`</repository>`
`<snapshotRepository>`
`<id>archiva.snapshots</id>`
`<name>Internal Snapshot Repository</name>`
`<url>http:``//nexus.d.xiaomi.net/nexus/content/repositories/snapshots/`
`</url>`
`</snapshotRepository>`
`</distributionManagement>`
5.從遠程倉庫解析依賴的機制
對于nsapshot
6.鏡像
`<mirrors>`
`<mirror>`
`<!--This sends everything ``else` `to /``public` `-->`
`<id>nexus</id>`
`<mirrorOf>*</mirrorOf>`
`<url>http:``//nexus.d.xiaomi.net/nexus/content/groups/public</url>`
`</mirror>`
`</mirrors>`
7.倉庫搜索 https://mvnrepository.com/
五. 生命周期和插件
5.1 什么是生命周期
在執(zhí)行maven命令時,其實都對應了一個生命周期柜思,對應的生命周期岩调,maven都做了什么呢,其實每個生命在周期赡盘,maven都綁定了默認的插件來完成相應的目標
每個生命周期都可以綁定一個或多個插件行為号枕,如下圖編譯實際是由mavne-compiler-pluin完成,測試是由maven-surefire-plugin完成
5.2 三套生命周期
5.2.1 clean生命周期
clean生命周期的目的是清理項目陨享,包含3個階段
1)pre-clean執(zhí)行一些清理前需要完成的工作葱淳。
2)clean清理上一次構建生成的文件
3)post-clean執(zhí)行清理后需要完成的工作
5.2.2 default生命周期
5.2.3site生命周期
5.3 命令行與生命周期
mvn clean 執(zhí)行celan生命周期的pre-clean和clean階段
mvn clean package 執(zhí)行clean生命周期pre-clean和clean階段,default生命周期的validate到package階段
mvn clean deploy
5.4 插件目標和插件綁定
插件綁定:生命周期的階段與插件的目標相互綁定抛姑,完成某個具體的構建任務
5.5 插件的內置綁定和自定義綁定
clean生命周期的clean階段赞厕,刪除項目輸出目錄
打jar包的default生命周期內置的插件綁定
自定義綁定
`<build>`
`<plugins>`
`<plugin>`
`<artifactId>maven-source-plugin</artifactId>`
`<version>``3.0``.``1``</version>`
`<executions>`
`<execution>`
`<id>attach-sources</id>`
`<phase>``package``</phase>`
`<goals>`
`<goal>jar</goal>`
`</goals>`
`</execution>`
`</executions>`
`</plugin>`
`</plugins>`
`</build>`
有些插件默認有綁定的生命周期,所以我們看到有時侯不需要指明phase定硝,可以用下面的命令查看插件綁定的phase信息
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:3.0.1 -Ddetail
5.6 插件配置
命令行插件配置
-D參數值=value皿桑,例如maven-surefire-plugin 的skipTests(不執(zhí)行也不編譯), maven.test.skip(不執(zhí)行但是會編譯)
mvn clean package -DskipTests=true
pom中插件配置
`<plugin>`
`<artifactId>maven-compiler-plugin</artifactId>`
`<configuration>`
`<source>${java.version}</source>`
`<target>${java.version}</target>`
`<encoding>UTF-``8``</encoding>`
`</configuration>`
`</plugin>`
`<plugin>`
`<groupId>org.apache.maven.plugins</groupId>`
`<artifactId>maven-enforcer-plugin</artifactId>`
`<executions>`
`<execution>`
`<id>enforce-ban-duplicate-classes</id>`
`<goals>`
`<goal>enforce</goal>`
`</goals>`
`<configuration>`
`<fail>``true``</fail>`
`<failFast>``true``</failFast>`
`<rules>`
`<bannedDependencies>`
`<searchTransitive>``true``</searchTransitive>`
`<message>Dependecy Check Failed!</message>`
`<excludes>`
`<exclude>org.springframework:spring-beans:(,``4.1``.``2``.RELEASE]</exclude>`
`<exclude>commons-logging:commons-logging</exclude>`
`</excludes>`
`</bannedDependencies>`
`<banDuplicateClasses>`
`<ignoreClasses>`
`<ignoreClass>javax.*</ignoreClass>`
`<ignoreClass>org.apache.commons.logging.*</ignoreClass>`
`<ignoreClass>org.apache.shiro.*</ignoreClass>`
`<ignoreClass>org.objectweb.asm.*</ignoreClass>`
`<ignoreClass>org.aspectj.*</ignoreClass>`
`</ignoreClasses>`
`<findAllDuplicates>``true``</findAllDuplicates>`
`</banDuplicateClasses>`
`</rules>`
`</configuration>`
`</execution>`
`</executions>`
`<dependencies>`
`<dependency>`
`<groupId>org.codehaus.mojo</groupId>`
`<artifactId>extra-enforcer-rules</artifactId>`
`<version>${extra-enforcer-rules.version}</version>`
`</dependency>`
`</dependencies>`
`</plugin>`
項目中常用插件:
maven-enforcer-plugin
maven-dependency-plugin
maven-clean-plugin
maven-compiler-plugin
maven-source-plugin
maven-war-plugin
maven-jar-plugin
maven-surefire-plugin
maven-resources-plugin
spring-boot-maven-plugin
六. 聚合與繼承
6.1 聚合與繼承
聚合
`<modules>`
`<module>auto-comment-domain</module>`
`<module>auto-comment-dao</module>`
`<module>auto-comment-manager</module>`
`<module>auto-comment-service</module>`
`<module>auto-comment-common</module>`
`<module>auto-comment-client</module>`
`<module>auto-comment-server</module>`
`<module>auto-comment-client-test</module>`
`</modules>`
繼承
`<parent>`
`<artifactId>auto-comment</artifactId>`
`<groupId>com.miui.media.auto</groupId>`
`<version>``0.0``.``7``-SNAPSHOT</version>`
`</parent>`
`<modelVersion>``4.0``.``0``</modelVersion>`
`<artifactId>auto-comment-client</artifactId>`
可繼承的pom元素
6.2 反應堆
(反應堆內的繼承和依賴)影響項目的構建實順序
反應堆外的依賴蔬啡,一定靠maven倉庫诲侮,在編譯前本地必須有;反應堆內的依賴箱蟆,本地倉庫可以沒有沟绪,是靠這次編譯的結果的
裁剪反應堆:例如mvn clean deploy -pl auto-comment-client -am -rf ../pom.xml
總結:結合實際使用的經驗來分析,還需要多用空猜,多總結绽慈。