maven的核心知識點
Maven學過java的都認識,但是大多數人只知道了他的依賴打包功能,對於其他核心功能理解並不深,下面我來講講maven的核心知識:
座標與依賴、
倉庫、
生命週期與外掛、
模組聚合、
模組繼承
等概念。並通過一個開發Maven外掛的例項來深入瞭解Maven的核心機制. 而對於 如何配置Maven、Nexus私服、Jenkins持續整合、Maven測試、構建Web、資源過濾、自定義Archetype 等相對簡單、講解繁瑣且網上有大量實踐案例的內容沒有涉及. 本文的目標是希望讀者能夠通過本文能對Maven核心原理有個相對深入的理解.
座標與依賴
為了能夠自動化的解析任何一個java構件,maven必須將他們唯一的標識,這就是依賴管理的底層基礎,座標————maven的座標為java引入了秩序,任何一個構件都必須為自己定義一個座標,如groupid,artifactId、version、packaging、classfier:
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
<packaging>jar</packaging>
groupId: 定義當前模組隸屬的實際Maven專案, 表示方式與Java包類似 groupId不應直接對應專案隸屬的公司/組織(一個公司/組織下可能會有很多的專案).
artifactId: 定義實際專案中的一個Maven模組 推薦使用專案名作為artifactId字首, 如:commons-lang3以commons作為字首(因為Maven打包預設以artifactId作為字首)
version :
packaging: 定義Maven專案打包方式, 通常打包方式與所生成構件副檔名對應 有jar(預設)、war、pom、maven-plugin等.
classifier: 用來幫助定義構建輸出的一些附屬構件(如javadoc、sources) 不能直接定義專案的classifier(因為附屬構件不是由專案預設生成, 須有附加外掛的幫助)
依賴:
maven最出名的就是maven的依賴管理,用了之後,我們不需再去開源網站一一下載元件,只需一個依賴宣告即可:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.7.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
<optional>false</optional>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
依賴傳遞\
maven的依賴傳遞機制會自動幫助我們載入我們依賴包的依賴,如:我們的專案依賴了spring-core, 而spring-core又依賴了commons-logging:
有了依賴傳遞機制, 在專案中添加了spring-core依賴時就不用再去考慮它依賴了什麼, 也不用擔心引入多餘的依賴. Maven會解析各個直接依賴的POM, 將必要的間接依賴以傳遞性依賴的形式引入到當前目錄中(inherits from its parents, or from its dependencies, and so on).
(依賴調節原則: 1. 路徑最近者優先; 2. 第一宣告者優先.)
依賴管理
Maven提供了dependency外掛可以對Maven專案依賴檢視以及優化, 如
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
Maven 倉庫
Maven 中, 任何一個依賴、外掛或專案構建的輸出, 都可稱為構件, 而Maven倉庫就是集中儲存這些構件的地方.
maven有兩類倉庫,本地倉庫和遠端倉庫,當maven根據座標去尋找構件的時候,maven會先找本地倉庫,如果沒有再去遠端倉庫去下載
本地倉庫:預設地址是~/.m2/,一個構件只有在本地倉庫存在後才能被maven專案所引用。
遠端倉庫也分為兩類:中央倉庫和私服。
中央倉庫:當我們建立maven專案時,原始的本地倉庫是空的,所以我們要有一個預設的遠端的倉庫提供我們去下載,中央倉庫就是這樣的倉庫。
私服:
私服屬於一種特殊的遠端倉庫,通過代理廣域網的遠端倉庫,maven使用者傳送下載外掛請求,私服收到後如果不存在該構件就去找中央倉庫去下載,並快取下來,再為使用者提供下載服務,此外如果在外部中央倉庫沒有的構件,如公司內部的外掛,maven也可以上傳到私服,供公司其他maven下載使用。架設私服需對pom做如下配置:
<project >
...
<distributionManagement>
<repository>
<id>releases</id>
<url>http://mvn.server.com/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<url>http://mvn.server.com/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
repository表示釋出版本構件的倉庫, snapshotRepository代表快照版本的倉庫.
id為該遠端倉庫唯一標識, url表示該倉庫地址.
配置正確後, 執行$ mvn clean deploy則可以將專案構建輸出的構件部署到對應配置的遠端倉庫.
注: 往遠端倉庫部署構件時, 往往需要認證: 需要在settings.xml中建立servers元素, 其id與倉庫的id匹配, 詳見: Password Encryption.
生命週期與外掛
maven將所有專案的構建過程都統一抽象成生命週期:專案的清理,初始化,編譯,測試,打包,整合測試,驗證,部署,站點生成….
幾乎所有的專案都能對映到這些生命週期上去,但是生命週期是抽象的,任務執行都是靠外掛來完成,每個生命週期階段都由一個或多個外掛完成,maven為大多數步驟綁定了預設的外掛,當然如果需要可以自定義外掛。
Maven 擁有三套相互獨立的生命週期: clean、default 和 site, 而每個生命週期包含一些phase階段, 階段是有順序的, 並且後面的階段依賴於前面的階段. 而三套生命週期相互之間卻並沒有前後依賴關係, 即呼叫site週期內的某個phase階段並不會對clean產生任何影響.
clean生命週期的目的是清理專案:
執行如$ mvn clean;
default生命週期定義了真正構建時所需要執行的所有步驟:
執行如$ mvn clean install;
site生命週期的目的是建立和釋出專案站點: Maven能夠基於POM所包含的資訊,自動生成一個友好的站點,方便團隊交流和釋出專案資訊
執行命令如$ mvn clean deploy site-deploy;
外掛
生命週期的階段phase與外掛的目標goal相互繫結, 用以完成實際的構建任務. 而對於外掛本身, 為了能夠複用程式碼,它往往能夠完成多個任務, 這些功能聚集在一個外掛裡,每個功能就是一個目標.
如:$ mvn compiler:compile: 冒號前是外掛字首, 後面是該外掛目標(即: maven-compiler-plugin的compile目標).
而該目標綁定了default生命週期的compile階段:
自定義繫結
除了內建繫結以外, 使用者還能夠自定義將某個外掛目標繫結到生命週期的某個階段上. 如建立專案的原始碼包, maven-source-plugin外掛的jar-no-fork目標能夠將專案的主程式碼打包成jar檔案, 可以將其繫結到verify階段上:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
executions下每個execution子元素可以用來配置執行一個任務.
maven-help-plugin
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin[:3.0.0] [-Ddetail] [-Dgoal=jar-no-fork]