原文地址: pjmike的博客java
上週去實習入職,領完電腦裝maven環境的時候被gank了,覺得本身裝好了,settings.xml文件也導入了,鏡像也換成了國內阿里雲鏡像了,結果搭建maven項目時發現,POM.xml文件導不進依賴項,提示錯誤,並且使用IDEA編寫maven依賴項沒有自動提示功能。mysql
通過一番折騰,發現是首先公司使用的IDEA社區版,功能並無專業版強大,用慣了專業版着實不習慣,第二個是個人settings.xml文件裏的阿里雲鏡像寫錯了,由於是直接在網上找的,看上去都差很少,其實倒是本身踩到了坑。後來師兄給了我一個公司特定版本的setting.xml配置文件才搞好。linux
從這個小問題,我也意識到我本身對Maven的掌握仍是不夠,因此纔有這篇文章對Maven的一些知識點進行系統性的學習,並概括總結。git
"對你遇到每個知識點要有一個系統的認識",忘記在哪看到的了,感受挺受用的。github
Maven的倉庫分爲兩類: 本地倉庫和遠程倉庫,當maven根據座標尋找構件的時候,它首先會查看本地倉庫,若是本地倉庫存在此構件,則直接使用,若是不存在,或者須要查看是否有更新的構件版本,Maven就會去遠程倉庫查找,發現須要的構件以後,下載到本地倉庫再使用。若是本地倉庫和遠程倉庫都沒有須要的構建,就會報錯。spring
中央倉庫是Maven核心自帶的遠程倉庫,它包含了絕大部分開源的構建,在默認配置下,當本地倉庫沒有maven須要的的構件時,它就會嘗試從中央倉庫中下載。sql
私服是另外一種特殊的遠程倉庫,爲了節省帶寬和事件,應該在局域網內架設一個私有的倉庫服務器,用其代理全部外部的遠程倉庫,內部的項目還能部署到私服上供其餘項目使用。緩存
默認狀況下,不論是在Windows仍是linux下,每一個用戶在本身的用戶目錄下都有一個路徑名爲.m2/repository/的倉庫目錄。服務器
有時候,由於某些緣由(例如C盤空間不夠),用戶會想要自定義本地倉庫目錄地址,這時,能夠編輯文件~/.m2/settings.xml,設置localRepository想要的倉庫地址,例如:框架
<localRepository>d:maven/maven.m2/repository</localRepository>
複製代碼
默認狀況下,~/.m2/settings.xml文件是不存在的,用戶須要從maven安裝目錄下/conf/settings.xml文件再進行編輯。
一個構件只有在本地倉庫以後,才能由其餘maven項目使用。
安裝好maven以後,若是不執行任何maven命令,本地倉庫目錄是不存在的,當用戶輸入第一條maven命令以後,maven纔會建立本地倉庫,而後根據配置和須要,從遠程倉庫下載構件到本地倉庫
大部分遠程倉庫都不須要認證,可是仍是有些倉庫須要認證,認證配置以下:
<server>
<id>deploymentRepo</id>
<username>repouser</username>
<password>repopwd</password>
</server>
複製代碼
本地原始的本地倉庫是空的,maven必須知道至少一個可用的遠程倉庫,才能在執行maven命令的時候下載到須要的構件,中央倉庫就是這樣一個默認的遠程倉庫,maven的安裝文件自帶了中央倉庫的配置。/MAVEN_HOME/lib/maven2.2x-uber.jar
私服是一種特殊的遠程倉庫,它是架設到局域網內的倉庫服務,私服代理廣域網上的遠程倉庫,供局域網內的maven用戶使用。當maven須要下載構件的時候,它從私服請求,若是私服不存在該條件,則從外部的遠程倉庫下載,緩存到私服上以後。
若是倉庫X能夠提供倉庫Y存儲的全部內容,那麼就能夠認爲X是Y的一個鏡像,換句話說,任何一個能夠從倉庫Y得到的構件,都可以從它的鏡像中獲取。
好比說,maven.net.cn/content/gro… 是中央倉庫 repo1.maven.org/maven2/ 在中國的鏡像,因爲地理位置的因素,該鏡像每每可以提供比中央倉庫更快的服務。在國內咱們更多的是使用阿里雲提供的鏡像服務:
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
複製代碼
在maven的世界中,任何一個項目都有本身的版本,版本的值多是1.0.0,1.3-alpha-4,2.0,2.1-SNAPSHOT等
那爲何還區分穩定版和快照版呢?好比你接到一個需求,針對公司的二方庫進行開發,新增某某接口等,可是你的需求不是很穩定,須要總是修改二方庫裏的內容,而公司某項目A又要依賴該二方庫,若是沒有快照版本,那麼二方庫每次修改好了,都會指定一個新的版本給項目A,項目A每次又要修改二方庫的版本,這樣就會顯得很是麻煩。
而Maven的快照版本機制就是爲了解決上述問題的,項目A只須要引入快照版本號,好比2.1-SNAPSHOT版本,由於是快照版本,針對二方庫的每次修改而且發佈後,在發佈過程當中,maven會自動爲構件打上時間戳,有了該時間戳,Maven就能夠隨時找到倉庫中該構件2.1-SNAPSHOT版本最新的文件,也就是說項目A能夠拉取到最新的版本內容。
默認狀況下,Maven天天檢查一次更新,固然用戶也可使用命令行-U參數強制讓maven檢查更新,如 mvn clean install -U
maven的生命週期就是爲了對全部的構建過程進行抽象和統一,這個生命週期包含了項目的清理、初始化、編譯、測試、打包、集成測試、驗證、部署和站點生成等幾乎全部構建步驟,可是maven的生命週期是抽象的,這意味着生命週期自己不作任何實際的工做,在maven的設計中,實際的任務都交給插件來完成。
maven有三個內置的構建生命週期:default、clean和site,可是平時工做中咱們更多的關注的是maven更加細分的生命週期階段:
階段的執行是按順序的,一個階段執行完成以後纔會執行下一個階段,好比執行mvn install命令,實際上它會執行install階段以前的全部階段,而後纔會執行install階段自己。
前面就提到過在maven的設計中,實際的任務(好比編譯源代碼)是交給插件來完成的,下面展現幾個經常使用的插件:
maven的一大功能就是管理項目依賴,爲了能自動化解析任何一個Java構件,maven就必須將它們惟一標識,這就依賴管理的底層基礎——座標,也就是GAV,即groupId artifactId version,由這三個屬性能夠惟一肯定一個jar包
如下面這個依賴項爲例
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.4.RELEASE</version>
<scope>test</scope>
</dependency>
複製代碼
除了GAV,仍是一個scope配置,其實就是依賴的範圍,依賴範圍就是用來控制依賴與三種classpath(編譯 classpath、測試classpath、運行classpath)的關係,Maven主要有如下幾種依賴範圍:
談到依賴,就不得不提使用maven可能碰到的依賴衝突問題,當一個項目中不一樣的Jar包依賴了相同的jar包時,此時就會發生依賴衝突的問題,爲了不衝突的發生,maven使用如下幾種策略來解決衝突:
那麼上面只是兩種策略,具體如何作呢?有兩種作法,手動分析衝突並解決和使用maven helper插件
mvn dependency:tree -Dverbose -Dincludes=commons-logging:commons-loggging
,該命令將打印出全部依賴了groupId和artifactId都爲commons-logging的jar包的依賴路徑。以下所示爲聚合:
<packaging>pom</packaging>
<modules>
<module>module-1</module>
<module>module-2</module>
<module>module-3</module>
</modules>
複製代碼
父POM:
<groupId>com.pjmike</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
</dependencies>
</dependencyManagement>
複製代碼
子POM,引入父POM
<!-- 指定parent,說明是從哪一個pom繼承 -->
<parent>
<groupId>com.pjmike</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 指定相對路徑 -->
<relativePath>../maven-parent</relativePath>
</parent>
<!-- 只須要指明groupId + artifactId,就能夠到父pom找到了,無需指明版本 -->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
複製代碼
使用dependencyManagement可對依賴進行管理,子類只要不引用這個裏面寫的依賴,則不會添加,這樣防止了重複加包,若是不使用dependencyManagement,那麼只要寫了dependency,子pom中會所有添加到依賴中。
下面列舉一些比較常見的maven命令
下面總結一個maven相關知識的思惟導圖,以下圖
上面總結的maven知識點並非特別全,更多關於maven的講解能夠參閱《maven實戰》這本書。