Maven 簡介 Maven 是一種聲明式項目管理工具,,通過在 POM 中配置 'who','what','where'等信息,,即可滿足編譯,、測試、打包,、發(fā)布等項目構(gòu)建需求,。聲明式的好處是,用戶無需關(guān)心構(gòu)建工具的實現(xiàn)細(xì)節(jié),,只需在 pom.xml 中配置好項目名,,依賴等基礎(chǔ)信息即可。壞處是,,實現(xiàn)自定義的構(gòu)建邏輯,,相對復(fù)雜。(Maven 也提供了插件,,如:maven-antrun-plugin,,來運(yùn)行用戶自定義腳本。當(dāng)然,,插件最終 apply 到 Maven 的方式最終仍然是聲明式的,,即需要在 POM 中聲明插件運(yùn)行時機(jī)和插件相關(guān)配置。) 相對應(yīng)地,,Make 和 Ant 等構(gòu)建工具是過程式項目管理工具,,用戶需要編寫構(gòu)建腳本并組織各腳本的依賴關(guān)系,。過程式項目管理工具好處是,,用戶自由度很大;壞處是,,項目管理經(jīng)驗無法復(fù)用,,構(gòu)建腳本編寫較為復(fù)雜。 POM 基本概念 POM 文件是Maven的核心文件,,包含項目構(gòu)建相關(guān)的所有配置信息,,如:項目源代碼目錄,class 文件輸出目錄等,。Maven 執(zhí)行 goal 時,,會首先讀取當(dāng)前目錄的 POM 文件,然后執(zhí)行對應(yīng) goal,。 Super POM Super POM 是 Maven 的默認(rèn) POM,。除顯式聲明以外,所有的POM都繼承自Super POM. Super POM 中配置了默認(rèn)的倉庫地址,,基本的 Plugin 和源代碼路徑等配置,。Super POM 內(nèi)容如下: <project> <modelVersion>4.0.0</modelVersion> <!-- NOTE: 依賴 repo 和 插件repo默認(rèn)倉庫地址--> <repositories> <!-- ....默認(rèn)repo --> </repositories> <pluginRepositories> <pluginRepository> <!-- ....默認(rèn)repo --> </pluginRepository> </pluginRepositories> <!-- NOTE: 項目默認(rèn)配置,如:mian代碼目錄,,--> <build> <directory>${project.basedir}/target</directory> <outputDirectory>${project.build.directory}/classes</outputDirectory> <finalName>${project.artifactId}-${project.version}</finalName> <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory> <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory> <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory> <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory> <resources> <resource> <directory>${project.basedir}/src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>${project.basedir}/src/test/resources</directory> </testResource> </testResources> <pluginManagement> <!-- NOTE: These plugins will be removed from future versions of the super POM --> <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) --> <plugins> <!-- ....這里是一系列的默認(rèn)插件 --> </plugins> </pluginManagement> </build> </project> Project Inheritance VS Project Aggregation
下圖展示了 Presto 的 POM 結(jié)構(gòu),,Presto 項目中既有項目繼承(繼承自io.airlift:airbase:80)也有項目聚合(多個模塊)。 Lifecycle Maven的生命周期就是為了對所有的構(gòu)建過程進(jìn)行抽象和統(tǒng)一,。 Maven從大量項目和構(gòu)建工具中學(xué)習(xí)和反思,,然后總結(jié)了一套高度完善的、易擴(kuò)展的生命周期,。 Maven 生命周期包含項目清理,、初始化、編譯,、測試,、打包、集成測試,、驗證,、部署和站點生成等幾乎所有構(gòu)建步驟。也就是說,,幾乎所有項目的構(gòu)建,,都能映射到這樣一個生命周期上。 Lifecycle 是抽象的概念,,生命周期本身不做任何實際工作,。 Maven 設(shè)計中,實際工作都交由插件完成,。 Lifecycles VS Phases Maven 有三套獨立的 Lifecycle:default,、clean 和 site,每個 Lifecycle 包含多個 Phase,。 下圖詳細(xì)的展示了Lifecycle 和 Phase的關(guān)系,。 Default default生命周期定義了真正構(gòu)建時所需要執(zhí)行的所有步驟,它是所有生命周期中最核心的部分,,其包含的階段如下:
Clean clean 生命周期的目的主要是清理項目。
Site site 生命周期用于生成代碼站點文檔并發(fā)布至對應(yīng)Web Server,。
Plugins 一個 Plugin 包含多個goal,來完成項目構(gòu)建的實際工作,,如:Compiler plugin 有兩個goal compile 和 testCompile,,分別用于編譯main代碼與編譯test代碼。下圖是default生命周期的插件內(nèi)置綁定與具體goal的綁定關(guān)系: 常用 Plugin maven-shade-plugin maven-shade-plugin 是一個很強(qiáng)大的 Maven 插件,,可以用來relocate 包名,,解決依賴沖突問題;也可以生成一個可執(zhí)行Jar包(又稱 Uber Jar),。下面我們就簡單介紹下這兩個功能使用方法,。 Relocation 我們以shade hive-exec 中的guava包進(jìn)行說明。(hive-exec 會依賴calcite的代碼,,calcite代碼也會依賴guava包),。 shaded-exec pom.xml: shaded-exec 中 calcite 代碼: 結(jié)論:maven-shade-plugin 會對滿足對應(yīng)pattern的所有class文件進(jìn)行relocate,不會區(qū)分該class文件是否是本項目代碼編譯產(chǎn)生,。 Executable Jar 結(jié)論:默認(rèn)情況下,,maven-shade-plugin 產(chǎn)生的 shaded jar,包含當(dāng)前項目class文件以及compile依賴。這也是為什么有時候可以通過修改依賴的scope,,即可影響JAR內(nèi)容的,。然而,如果項目中僅使用了默認(rèn)的jar plugin,,那么修改依賴scope,,將不會影響輸出的Jar的內(nèi)容了,里面將永遠(yuǎn)只包含本項目的class,。 maven-antrun-plugin maven-antrun-plugin 使Maven可以運(yùn)行我們自定義的腳本,,靈活控制構(gòu)建過程。 如下所示 pom.xml 就通過 maven-antrun-plugin 在 compile 階段打印出 Maven 的四類class path,,幫助我們定位編譯問題,。
PS:當(dāng)插件目標(biāo)被綁定到不同的生命周期階段的時候,其執(zhí)行順序會由生命周期階段的先后順序決定,。如果多個目標(biāo)被綁定到同一個階段,,它們的執(zhí)行順序會是怎樣? 答:當(dāng)多個插件目標(biāo)綁定到同一個階段的時候,,這些插件聲明的先后順序決定了目標(biāo)的執(zhí)行順序,。 Dependency Mechanism Maven 作為一個項目管理工具,依賴管理是必不可少的,。 Maven 依賴坐標(biāo) Maven 坐標(biāo)為各種構(gòu)件引入了秩序,,任何一個構(gòu)件都必須明確定義自己的坐標(biāo),,而一組Maven坐標(biāo)是通過一些元素定義的,。Maven 坐標(biāo)一般可以認(rèn)為是一個五元組,,即:(groupId,artifactId,,version,,type,classifier),。下面進(jìn)行詳細(xì)說明:
上述五個元素中,groupId,、artifactId,、version是必須定義的,type是可選的(默認(rèn)為jar),,而classifier是取決于對應(yīng)依賴是否提供。 <project xmlns='http://maven./POM/4.0.0' xmlns:xsi='http://www./2001/XMLSchema-instance' xsi:schemaLocation='http://maven./POM/4.0.0 https://maven./xsd/maven-4.0.0.xsd'> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <type>jar</type> <scope>test</scope> <optional>true</optional> </dependency> <dependency> <groupId>mygroup</groupId> <artifactId>myjar</artifactId> <version>1.0</version> <classifier>jdk11</classifier> </dependency> <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-common</artifactId> <version>1.0</version> <scope>test</scope> <type>test-jar</type> </dependency> </dependencies> </project> 依賴 Scope 依賴Scope作用有兩個: 1. 限制依賴傳遞 2. 控制依賴是否出現(xiàn)在各個classpath中 Maven 中有五種依賴scope,,分別是:compile,provided,runtime,test和system,。 下面是引用自Maven官網(wǎng)的說明: Maven中大致可以分成四類class path:
結(jié)合依賴的scope和四類classpath,總結(jié)出 classpath 與 依賴的關(guān)系,,如下圖: 依賴傳遞
當(dāng)在A中配置:
則會自動導(dǎo)入 C 包,, 詳細(xì)的關(guān)系傳遞如下表 : 依賴調(diào)節(jié) 依賴調(diào)解遵循以下兩大原則:路徑最短優(yōu)先,、聲明順序優(yōu)先。
A --> B --> X(1.1) // dist(A->X) = 2 A --> C --> D --> X(1.0) // dist(A->X) = 3 此時,,Maven可以按照第一原則自動調(diào)解依賴,結(jié)果是使用X(1.1)作為依賴,。
當(dāng)路徑長度相同,則需要根據(jù)A直接依賴包在pom文件中的先后順序來判定使用那條依賴路徑,,如果次級模塊相同則向下級模塊推,,直至可以判斷先后位置為止。 <!-- A pom.xml --> <dependencies> ... dependency B ... dependency C </dependencies> 假設(shè)依賴B位置在依賴C之前,,則最終會選擇X(1.1)依賴,。
總結(jié) 1.Maven 是一種聲明式的項目管理工具。 2.Maven 有3套獨立的生命周期,,具體的工作交由插件 goal 完成,。 3.修改依賴Scope,并不能控制Jar的內(nèi)容,。 Hey! 我是小蘿卜算子 |
|