maven pom.xml解析、命令说明、依赖传递、继承、聚合、properties、build、依赖范围、版本仲裁、profile
maven是當前Java項目中用到最多的依賴管理工具。最開始的項目比較小引入的依賴包也少所以可以通過手動加載jar包的方式來管理依賴包;但隨著項目越來越復雜各種大小框架層出不窮,一個項目的開發往往依賴的jar包成百上千,此時再去手動依賴找到這些jar包并且找到它們相互依賴的版本無疑是一個巨大的工程,此時需要一個能夠簡單解決掉這些依賴關系的工具;maven就解決了這一類的難題,并且maven還可以做項目構建,比如一個spring boot項目打包成一個jar包給項目部署也帶了極大的方便。
一、POM文件解析
下面的示例文件列舉了大部分常用的pom.xml的標簽,不一定每個項目都會用到所有的標簽
三者關系:
my-test-member 是父工程/總工程(聚合角度)
my-test-member-api 和 my-test-member-biz 都是子工程/聚合工程(聚合角度)
my-test-member pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>org.my.test.member</groupId><artifactId>my-test-member</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version> <!-- modules:配置工程聚合--><modules><!-- module:配置一個具體的聚合模塊 --><module>my-test-member-api</module><module>my-test-member-biz</module></modules><!-- properties:定義屬性值 --><properties><!-- 自定義屬性mysql版本號,對于自定義屬性來說名稱自己寫 --><mysql.version>8.0.17</mysql.version><swagger.version>2.8.0</swagger.version><mybatis.plus.version>3.3.2</mybatis.plus.version><spring.boot.version>2.3.5.RELEASE</spring.boot.version></properties><!-- 使用dependencyManagement標簽配置對依賴的管理 --><!-- 被管理的依賴并沒有真正被引入到工程 --><dependencyManagement><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><!-- 使用properties中自定義的屬性值mysql版本號,好處是如果有多處使用該版本號,直接修改properties中的mysql版本號屬性值即可 --><version>${mysql.version}</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>${swagger.version}</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis.plus.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>${spring.boot.version}</version></dependency></dependencies></dependencyManagement><build><pluginManagement><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring.boot.version}</version></plugin></plugins></pluginManagement></build></project>my-test-member-api pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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"><parent><artifactId>my-test-member</artifactId><groupId>org.my.test.member</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>org.my.test.member.api</groupId><artifactId>my-test-member-api</artifactId><dependencies><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency></dependencies> </project>my-test-member-biz pom.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- project:根標簽,表示對當前工程進行配置、管理 --> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><!-- parent:給當前工程配置父工程 --><parent><!-- 通過坐標信息定位父工程 --><artifactId>my-test-member</artifactId><groupId>org.my.test.member</groupId><version>1.0-SNAPSHOT</version></parent><!-- modelVersion:從maven2.x版本開始固定4.0.0,代表當前pom.xml所采用的標簽結構 --><modelVersion>4.0.0</modelVersion><!-- 當前Maven工程的坐標信息,其他項目如果要依賴當前maven項目則使用以下的坐標信息 --><!-- groupId:一般表示公司或組織開發的某個項目 --><!-- artifactId:一般表示項目下的某個模塊 --><!-- version:當前模塊的版本 --><!-- 也是安裝該jar包后在本地倉庫中的路徑 如:com\my\test\member\my-test-product-biz\0.0.1-SNAPSHOT\my-test-member-biz-0.0.1-SNAPSHOT.jar --><!-- 如果配置了父工程(parent標簽),如果groupId和父工程一樣則可以不寫groupId,如果version和父工程一樣也可以不寫version,但是artifactId必須要寫 --><groupId>com.my.test.member</groupId><artifactId>my-test-member-biz</artifactId><version>0.0.1-SNAPSHOT</version><!-- 當前Maven工程的打包方式,可選值有下面四種:默認值jar --><!-- jar:表示這個工程是一個Java工程,打包結果jar包,創建Java工程命令:mvn archetype:generate --><!-- war:表示這個工程是一個Web工程(傳統的jsp工程),打包結果war包,創建Web工程命令:mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4選擇創建方式編號比如quickstart,會提示輸入groupId、artifactId、version等,會生成web.xml、WEB-INF、index.jsp等文件或目錄,如果沒有java目錄的話,需要自己在main目錄下創建java目錄;Web工程可依賴Java工程,也就是war包里面可以依賴jar包,不能jar包依賴war包 --><!-- pom:表示這個工程是“管理其他工程”的工程,比如該工程是一個父級工程則定義為pom,創建命令:mvn archetype:generate但是packaging時jar需要改成pom --><!-- maven-plugin:定義當前工程為maven插件即自定義maven插件的時候用到,但是基本不會有自定義插件的場景 --><packaging>jar</packaging><!-- name:當前工程的名稱 --><name>my-test-member-biz</name><!-- url:maven官網地址 --><url>http://maven.apache.org</url><!-- description:當前工程的說明 --><description>測試微服務用戶服務</description><!-- properties:在maven中定義屬性值,可以是指定maven自帶的屬性值,也可以是自定義屬性值;標簽中間是屬性值,標簽本身是屬性 --><properties><java.version>1.8</java.version></properties><!-- dependencies:指定依賴信息 --><dependencies><!-- dependency:指定一個具體的依賴信息,通過maven的坐標信息指定 --><dependency><groupId>org.my.test.member.api</groupId><artifactId>my-test-member-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><!-- scope:指定當前依賴的范圍,默認值compile,總共以下6種可選值:compile/test/provided/system/runtime/import--><!-- compile:默認值,compile范圍的jar包,可以在開發時正常使用該jar包里面的類方法等(可以在main/test目錄下的程序中正常使用),并且項目打包的時候會將該jar包打入到項目生成的jar或war包中,即該jar包會被main目錄中的程序使用且不屬于provided的情況如:spring-boot-starter --><!-- test:test范圍的jar包,開發時可以在test目錄下的程序正常使用該jar包里面的類方法等,但是main目錄下的程序不能正常使用,并且項目打包的時候不會將該jar包打入到項目生成的jar或war包中,即僅作測試用的jar包定義該范圍如:junit --><!-- provided:provided范圍的jar包, 可以在開發時正常使用該jar包里面的類方法等(可以在main/test目錄下的程序中正常使用),并且項目打包的時候不會將該jar包打入到項目生成的jar或war包中,一般對于服務器已提供的jar包,但是開發過程中又需要用到該jar包則定義為provided(因為服務器本身已有該jar包,所以不需要在打包時帶入,以避免包臃腫和版本沖突),比如:servlet-api、jsp-api --><!-- system:本文后面有介紹 --><!-- runtime:本文后面有介紹 --><!-- import:本文后面有介紹 --><scope>test</scope><!-- excludes標簽配置依賴的排除 --><exclusions><!-- exclude標簽中配置一個具體的依賴排除 --><exclusion><!-- 指定要排除的依賴的坐標(不需要寫version) --><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><!-- 此處不寫版本在于父工程my-test-member中dependencyManagement中定義了該包的版本信息,如果寫上版本號則使用該pom中定義的版本,不寫則使用父工程定義的版本 --><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><!-- configuration 標簽:配置 spring-boot-maven-plugin 插件 --><configuration><!-- 具體配置信息會因為插件不同、需求不同而有所差異 --><!-- source:要求編譯器使用指定的jdk版本來兼容寫的源代碼 --><source>1.8</source><!-- target:源文件編譯后,生成的 *.class 字節碼文件要符合指定的 JVM 版本 --><target>1.8</target><!-- encoding:工程構建過程中讀取源碼時使用的字符集 --><encoding>UTF-8</encoding></configuration></plugin></plugins></build></project>約定優于配置
maven可以做依賴管理與項目構建,其中的項目構建的方便得益于maven提供的約定優于配置,比如項目打包需要編譯源文件、測試等等,那么需要知道源文件在哪、測試類在哪,這就體現了maven本身對于項目目錄結構的一個約定
約定優于配置優于編碼
二、maven常用命令
注意:使用 Maven 構建操作相關的命令時,必須進入到 pom.xml 所在的目錄。如果沒有在 pom.xml 所在的目錄運行 Maven 的構建命令,則會報錯(mvn -v這種和構建操作無關的命令則配置了PATH之后可以在任何目錄執行):
如果一個項目中有多個pom.xml則在哪個pom.xml目錄執行構建命令,就是對哪個工程的構建操作。
maven生命周期
生命周期的設定是為了讓maven工程構建過程自動化完成,總共設定了三個生命周期,生命周期中的每一個環節對應構建過程中的一個操作;一個工程構建一般會包含編譯、測試、打包、部署等等,如果沒有生命周期的設定;我們想要完成工程的部署,需要將編譯、測試、打包按照順序分別執行,有了生命周期的設定之后,我們只需要執行我們想要的結果操作即可,要實現該結果前面需要進行的操作,按照生命周期執行即可,而不需要手動去執行。比如某個生命周期包含有1->5這五個操作,那么我們執行操作3的話maven會在執行3之前將該生命周期中1和2順序執行。
注意:執行某個操作時maven會將該生命周期中,該操作之前的操作都執行,只是執行該生命周期前面的操作,不會執行其他生命周期的操作;比如:執行 install 命令,它屬于Default這個生命周期的命令,那么會將Default中install前面的命令都按照順序執行(也就是除了最后一步deploy,其他的操作都會按照順序執行),正因為這個設定執行maven命令的時候,每個生命周期執行一個命令即可,如果想要執行其他生命周期的操作需要和另外生命周期中的命令進行組合,而mvn clean install這個組合命令中,install屬于Default、clean屬于Clean這兩個命令不屬于一個生命周期,所以想要他們都執行需要進行組合命令,而因為會執行命令所屬生命周期的前面所有操作,所以沒必要將生命周期中的每個命令都寫上
maven插件
maven中構建工程相關的命令都是由maven插件最終執行,maven本身僅僅負責調度。使用方式如:
創建maven工程的命令:mvn archetype:generate 其中mvn是主命令、archetype:generate是子命令、archetype是插件、generate是目標。
一個插件可以對應多個目標,而每一個目標都和生命周期中的某一個環節對應。
比如Default 生命周期中有 compile 和 test-compile 兩個和編譯相關的環節,這兩個環節對應 compile 和 test-compile 兩個目標,而這兩個目標都是由 maven-compiler-plugin-3.1.jar 插件來執行的。
三、依賴傳遞與排除依賴
maven進行依賴時是通過本地maven倉庫進行的jar包導入,比如A依賴了B,如果B工程做了修改(不論是代碼或pom的修改),需要先安裝B工程到本地倉庫,否則本地倉庫還是上一次B的版本,即使A進行構建依賴的B還是未修改的;所以當被依賴工程B做了修改需要先安裝到本地倉庫,然后再構建A。
依賴傳遞
比如:A 依賴 B,B 依賴 C, A 沒有配置對 C 的依賴的情況下,A 里面是否可以使用 C
分情況看:
B 依賴 C 時使用 compile 范圍:可以傳遞
B 依賴 C 時使用 test 或 provided 范圍:不能傳遞,所以A需要C的 jar 包時,就必須在A里面明確配置依賴C才可以。
換言之就是A里面想要使用C的話,需要A依賴的這個B的jar包里面有C的jar包,也就是需要B依賴C的時候使用compile范圍,而不能是test 或 provided范圍。
依賴排除
比如:A 依賴 B,B 依賴 C, C可以傳遞到A中,但是A不需要B依賴的C,比如A中已經有一個其他版本的C的依賴了,為了避免jar包沖突,所以A需要使用本身配置的C而不是B依賴的C,那么此時就需要在A依賴B時排除掉B依賴的C,即在A的pom.xml中依賴B時使用exclusions標簽排除C。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><!-- excludes標簽配置依賴的排除 --><exclusions><!-- exclude標簽中配置一個具體的依賴排除 --><exclusion><!-- 指定要排除的依賴的坐標(不需要寫version) --><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency>四、繼承
和Java的繼承類似,Java繼承子類可以擁有父類的變量及方法;在maven中的繼承就發生在父工程和子工程中,子工程可以繼承父工程的依賴以及使用父工程中定義的版本信息,一般用于在父工程中做版本統一管理,子工程使用父工程定義的版本信息,避免整個項目中相同jar包各個子工程版本五花八門,最終導致依賴沖突或意料之外的異常信息;所以一般情況下父工程中需要將所有子工程的依賴都進行版本規范,每個子工程依賴本工程需要的依賴包即可(如果子工程導入依賴時不寫版本號則采用父工程定義的版本號,子工程寫了版本號則使用子工程定義的版本號),也可以考慮將所有子工程都會用到的依賴,放在父工程中,這樣所有子工程也會通過繼承的方式擁有這個依賴(不推薦,還是在父工程中只定義版本管理);子工程中使用 parent 標簽定義父工程;每個POM都有且僅有一個父POM(未定義parent的話就是默認的超級POM作為父POM),并且可以多級繼承;比如A工程繼承B工程,B工程繼承C工程,那么A工程中可以用到C工程定義的 dependencyManagement 。
父工程:
子工程:
<!-- parent:給當前工程配置父工程 --><parent><!-- 通過坐標信息定位父工程 --><artifactId>my-test-member</artifactId><groupId>org.my.test.member</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.my.test.member</groupId><artifactId>my-test-member-biz</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><dependencies><dependency><!-- 此處不寫版本在于父工程my-test-member中dependencyManagement中定義了該包的版本信息,如果寫上版本號則使用該pom中定義的版本,不寫則使用父工程定義的版本 --><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>POM的四個層級:
超級POM、父POM、當前POM、有效POM
超級POM:類似于Java中的Object類,超級POM是所有POM的頂級父類、如果某個POM未定義父POM,那么它的父POM就是這個超級POM;超級POM定義了如源文件存放的目錄、測試源文件存放的目錄、構建輸出的目錄……等等。
父POM:在POM中通過 parent 標簽指定的POM就是該POM的父POM。一個POM有且僅有一個父POM。
當前POM:當前工程的POM。
有效POM(effective POM):因為有繼承關系及依賴傳遞的存在,所以我們當前工程的POM定義的內容,并不是當前工程所有的POM內容,POM會按照繼承關系及依賴傳遞做疊加操作,最終得到的POM就是有效POM,也就是對當前工程依賴及相關設定最終產生效果的POM。
有效POM的疊加關系:在 POM 的繼承關系中,子 POM 可以覆蓋父 POM 中的配置;如果子 POM 沒有覆蓋,那么父 POM 中的配置將會被繼承(也就是說如果在繼承關系中有多個POM都對同一個內容進行了定義則離當前POM距離越近的配置生效,如果多個POM中只有一個POM對內容進行了定義則不管有多少級的繼承關系,這個內容都會生效。比如當前工程A繼承B繼承C,ABC都對a依賴做了配置,那么A中對a依賴的配置生效,如果只有C中做了c依賴配置,那么C中對c依賴的配置會生效,如果B和C都對b依賴做了配置,那么B中對b依賴的配置會生效)。按照這個規則,繼承關系中的所有 POM 疊加到一起,就得到了一個最終生效的 POM。
查看有效POM的命令:
五、聚合
定義一個“總工程”將各個“模塊工程”匯集起來,作為一個完整的項目;一般來說總工程也是父工程(繼承角度)乃至于最頂級的父工程,子工程則是模塊工程。好處是可以在總工程中執行maven命令,從而對總工程中定義的模塊工程都執行該命令,并且會自動梳理依賴關系,進行執行命令。通過在總工程中使用 modules 標簽定義模塊工程即可。
總工程/父工程:
循環依賴報錯如下:
DANGER[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:六、properties 屬性聲明及引用
使用 properties 標簽可以定義系統自帶的屬性值以及自定義屬性及屬性值,方式:
<properties><!-- 自定義屬性mysql版本號,對于自定義屬性來說名稱自己寫 --><mysql.version>8.0.17</mysql.version></properties>主要用途:
1、在當前 pom.xml 文件中引用屬性,比如依賴版本定義引用 properties 中的屬性,達到一處修改,全部版本都替換的效果。
2、資源過濾功能:在非 Maven 配置文件中引用屬性,由 Maven 在處理資源時將引用屬性的表達式替換為屬性值(下方 十、profile 標簽 中有講解)
查看屬性值:根據輸入表達式,輸出表達式結果:
mvn help:evaluate執行該命令后,會要求輸入表達式,然后輸出表達式的結果。
1、比如輸出剛剛定義的 mysql.version 的表達式就是
2、訪問系統屬性:比如Java系統屬性也就是通過 System.getProperties() 方法可以拿到的屬性,表達式就是:
${屬性名} 如:${java.runtime.name}3、訪問系統環境變量:比如JAVA_HOME,表達式就是:
${env.系統環境變量名} 如:${env.JAVA_HOME}4、訪問 project 屬性,也就是訪問當前POM中的元素值,表達式就是:
${project.元素名} 如:訪問當前POM的一級標簽表達式:${project.標簽名},如:${project.artifactId} 輸出當前POM的artifactId的值 訪問當前POM的子級標簽表達式:${project.標簽名.子標簽名},如:${project.parent.groupId} 輸出當前POM的父POM的groupId的值 訪問列表標簽表達式:${project.標簽名[下標]},如:${project.modules[0]} 輸出當前POM的modules標簽下的第一個值,${project.build.plugins[0]} 輸出當前POM的build標簽下的plugins標簽下的第一個值5、訪問 settings 全局配置,比如maven settings.xml配置文件中的屬性,表達式就是:
${settings.標簽名} 如:${settings.localRepository} 輸出settings.xml配置的本地倉庫的路徑七、build 標簽
build意為構建,意思就是在工程構建過程中的定制化操作,因為超級POM是每個POM的直接或間接父POM,所以每個工程的有效POM實際上其中的 build 都包含了超級POM中定義的 build 標簽內容;當有效POM中的 build 標簽內容(因為繼承關系包含所有父POM的build內容)不能滿足當前工程的構建的時候,那么我們就會在當前工程中定義 build 標簽內容,所以 build 標簽不是一定會存在當前工程中的。
build標簽大致包含三類子標簽:
1、定義約定的目錄結構
如:
2、備用插件管理
通過 pluginManagement 標簽在父POM中來管理插件版本和 dependencyManagement 在父POM中定義依賴版本意思一樣,子工程使用父工程中定義的插件時可以省略版本號,起到在父工程中統一管理插件版本的效果。
如:
父工程(在build標簽中使用pluginManagement標簽管理插件版本):
子工程(在build標簽中使用plugins導入父工程管理的插件時,可以不寫版本號,使用父工程定義的版本號,和繼承一樣,子工程可覆蓋父工程,即采用的版本是距離當前工程最近的工程中定義的版本):
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>spring-boot-maven-plugin 插件作用:
比如spring boot項目使用maven本身install的插件只會將工程代碼本身進行安裝生成jar包,但我們想要java -jar可以直接運行的jar包,除了工程代碼本身,還需要依賴的jar包、Servlet容器(如:Tomcat)、
通過 java -jar 方式可以直接啟動jar包相關的配置等;spring-boot-maven-plugin插件就可以實現上述功能。
3、生命周期插件
如:
解釋:
坐標:groupId、artifactId、version 標簽定義了插件的坐標,如果是 Maven 的自帶插件會省略 groupId
executions 標簽內可以配置多個 execution 標簽,execution 標簽內含義:
id:指定唯一標識
phase:關聯的生命周期階段
goals/goal:關聯指定生命周期的目標,goals 標簽中可以配置多個 goal 標簽,表示一個生命周期環節可以對應當前插件的多個目標。
configuration:對插件目標的執行過程進行配置,其中的標簽需要是插件本身定義的,如上面的 spring-boot-maven-plugin 插件中的 repackage 目標,配置 mainClass 標簽,這個 mainClass 就是 spring-boot-maven-plugin 插件中的類中的屬性,意思是指定spring boot項目的啟動類。
4、其他,如:
build 標簽典型應用:
除了上面提到的使用 spring-boot-maven-plugin 插件,用于生成 java -jar可直接運行的 jar 包外,另外就是用于指定jdk版本也是常用的功能:
為什么需要指定jdk版本:不指定jdk版本的情況下項目一般默認識別的jdk版本是1.5,那么這個時候如果我們在項目中的代碼,使用了jdk5以上版本的語法,比如jdk8的 Lambda 表達式 那么idea編輯器會提示這段代碼報錯,并且此時編譯或打包也會報錯。那么如果指定 jdk版本 的話一般可以在三個地方指定:
a、maven的 settings.xml 配置文件中的 profile 標簽指定:
b、當前工程的 pom.xml 中 build 標簽指定:
<!-- build 標簽:指定maven構建工程的定制化操作! --> <build><!-- plugins 標簽:指定需要用到的插件! --><plugins><!-- plugin 標簽:指定一個具體的插件 --><plugin><!-- 插件的坐標。此處引用的 maven-compiler-plugin 插件不是第三方的,是一個 Maven 自帶的插件。 --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><!-- configuration 標簽:配置 maven-compiler-plugin 插件 --><configuration><!-- 具體配置信息會因為插件不同、需求不同而有所差異 --><!-- source:要求編譯器使用指定的jdk版本來兼容寫的源代碼 --><source>1.8</source><!-- target:源文件編譯后,生成的 *.class 字節碼文件要符合指定的 JVM 版本 --><target>1.8</target><!-- encoding:工程構建過程中讀取源碼時使用的字符集 --><encoding>UTF-8</encoding></configuration></plugin></plugins> </build>c、當前工程的 pom.xml 中 properties 標簽指定:
<properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>三種方式區別:
a方式settings.xml 中配置:僅在本地生效,如果脫離當前 settings.xml 能夠覆蓋的范圍,則無法生效,這樣就可能會導致我們本地的maven settings.xml文件中做了相關設置,但是同事的本地maven倉庫卻沒有做該設置,那么我們本地可以編譯、打包該項目,同事拉取代碼之后卻無法完成編譯、打包操作;但是因為 settings.xml 是對整個maven的配置,所以對于本地的多個項目來說都能夠生效。
b、c方式在當前 Maven 工程 pom.xml 中配置:無論在哪個環境執行編譯等構建操作都有效,但僅僅對當前工程生效。
八、scope 依賴范圍
在 dependencies 中導入依賴的時候,每個依賴可以定義 scope 即依賴范圍。
默認值compile,總共有6種可選值:compile/test/provided/system/runtime/import
可選依賴:
在上面的 runtime 依賴范圍的例子中導入 spring-boot-devtools 包的時候,有一個 optional 標簽;該標簽就是配置可選依賴,意為可有可無;官方解釋為:比如Project X 依賴 Project A,A 中一部分 X 用不到的代碼依賴了 B,那么對 X 來說 B 就是『可有可無』的。簡單來說就是 標記了 optional 標簽為 true 的依賴就是這個包里面的功能很少會用到,所以不要這個依賴不影響工程正常功能,如果使用到了這個包里面的功能就需要導入這個依賴。
九、版本仲裁
出現版本仲裁的情況一定是工程依賴了一個jar包的不同版本,如果本來就是不同的依賴包則是做疊加操作,也就是在最終生成的有效POM中這些依賴包都存在。
如果是通過繼承方式得到的依賴包或者依賴版本管理是子工程覆蓋父工程也就是繼承關系中距離當前工程越近的聲明生效。
如果是依賴傳遞的方式,則采用兩種方式仲裁:
a、最短路徑優先
比如A工程依賴B工程依賴C工程依賴了 x-1.0 jar包、A工程依賴D工程依賴了 x-2.0 jar包,則在A工程中生效的 x jar包是D工程中依賴的 x-2.0 jar包。
b、路徑相同時先聲明者優先
比如A工程依賴B工程依賴了 y-1.0 jar包、A工程依賴D工程依賴了 y-2.0 jar包,此時對于A工程來說,想要依賴 y jar包,兩個版本的路徑長度一樣,那么對于依賴哪個 y jar包就是由A工程中的 pom.xml 中先聲明的B工程依賴還是D工程依賴決定。先聲明依賴B工程則是采用 y-1.0 jar包,先聲明依賴D工程則是采用y-2.0 jar包。
maven版本仲裁只是maven的一個依賴沖突的自動解決方案(在沒有人為干預的情況下按照以上規則進行仲裁),當通過maven本身的版本仲裁之后,項目功能沒問題可以正常運行,不需要多做關心;但是有些情況下通過版本仲裁得到的依賴會不滿足我們的使用要求,比如版本仲裁得到 1.0 版本,但是我們使用的該 jar包 中的某個方法,1.0 版本沒有(或者1.0版本的邏輯不滿足要求)這個方法在仲裁失敗的 2.0 版本中并且滿足要求,那么此時就只有人為干預讓 maven 依賴 2.0 版本;比如在當前工程中明確指定依賴的版本信息,或者通過 exclusion 標簽,排除 1.0 版本的依賴。
十、profile 標簽
在 Maven 中,使用 profile 機制來管理不同環境下的配置信息。并且解決同類問題的類似機制在其他框架中也有;比如生產環境、測試環境、開發環境的數據庫緩存連接等而且從模塊劃分的角度來說,持久化層的信息放在構建工具中配置也違反了『高內聚,低耦合』的原則。
默認 profile
在 pom.xml 中不在 profile 標簽內的配置,就是配置的默認 profile 。因為根標簽 project 下所有標簽相當于都是在設定默認的 profile。project 標簽下除了 modelVersion 和坐標標簽之外,其它標簽都可以配置到 profile 中。
使用順序
a、為每個環境聲明一個 profile
環境 A:profile A
環境 B:profile B
環境 C:profile C
b、激活某個環境的 profile
profile 配置地方
a、maven的 settings.xml 配置文件中的 profile 標簽:對本地工程都生效。比如上面配置 JDK 1.8。
b、pom.xml:僅對當前工程生效。
profile 標簽內容
a、profiles/profile 標簽
profile 代表某個配置并且配置可以有多個,由 profiles 標簽統一管理;所以 profile 配置在 profiles 標簽中。
profile 標簽中的配置會覆蓋 pom.xml 中的同級配置,所以 profiles 標簽通常是 pom.xml 中的最后一個標簽。
b、id 標簽
每個 profile 都必須有一個 id 標簽,指定該 profile 的唯一標識。這個 id 標簽的值會在命令行調用 profile 時被用到。命令格式(作為命令的參數被使用):-P<profile的id>,如:mvn compile -PjdkTest,其中 jdkTest 就是某個 profile 的 id 標簽的值;意思是在編譯的時候使用 profile id為 jdkTest 的配置進行編譯。
c、其他標簽
除了上面a b標簽是 profile 固定的之外,其他標簽是 project 跟標簽下除了 modelVersion 和坐標標簽,都可以配置到 profile 中;比如一個 profile 可以覆蓋項目的最終名稱、項目依賴、插件配置等各個方面以影響構建行為。
profile 激活
a、當 POM 中沒有在 profile 標簽里的配置就是默認的 profile,默認被激活。
b、基于環境信息激活,如:JDK 版本、操作系統參數、文件、屬性等等。一個 profile 一旦被激活,那么它定義的所有配置都會覆蓋原來 POM 中對應層次的元素。比如:
表示當 JDK 版本為 1.8 且 maven 版本為 3.5.4 時被激活(Maven 3.2.2 及之后的版本)
上面的例子有兩個激活條件則(多個激活條件也一樣):
Maven 3.2.2 之前:遇到第一個滿足的條件即可激活即或的關系。
Maven 3.2.2 開始:各條件均需滿足即且的關系。
c、命令行激活
列出所有激活的 profile,以及它們在哪里定義
執行maven指令時指定某個具體的 profile
mvn clean test -P<profile id> 如:mvn clean test -PjdkTest 指定清理測試時使用id為jdkTest的profile資源屬性過濾
Maven 能夠通過 profile 實現各不同運行環境切換,因為 Maven 提供了『資源屬性過濾』的機制。通過屬性替換實現不同環境使用不同的參數。
我們可以在當前工程的 pom.xml 文件中,定義每個環境的 profile 配置,然后maven構建工程時,指定使用某個環境的profile即可,比如定義數據庫連接信息,可以這樣定義:
第一步:在 pom.xml 中通過 profile 定義數據庫連接信息:
第二步:創建待處理的資源文件;如:application.properties(在上一步中定義的開啟資源過濾功能目錄是src/main/resources,所以需要將application.properties文件,創建在該目錄下)
dev.user=${dev.jdbc.user} dev.password=${dev.jdbc.password} dev.url=${dev.jdbc.url} dev.driver=${dev.jdbc.driver}第三步:執行 maven 構建工程的命令并指定使用對應環境的 profile
mvn clean install -PdevJDBC執行清理安裝命令時 會將 id 為 devJDBC 的profile配置,做資源過濾處理,效果就是會將 devJDBC 中配置的user、password、url、driver等信息,寫入到 application.properties 文件中的對應屬性上。application.properties 中 ${dev.jdbc.user} 對應 devJDBC 中的 <dev.jdbc.user>root</dev.jdbc.user> 也就是將 root 賦值給 dev.user屬性。
includes、excludes
有時會在 resource 標簽下配置 includes 和 excludes 標簽;作用是:
includes:指定執行 resource 階段時要包含到目標位置的資源
excludes:指定執行 resource 階段時要排除的資源
比如上面的 devJDBC profile的例子,其中的 includes 指的是在 resource 階段,需要將當前工程 resources 目錄下的所有 properties 文件包含到目標位置,excludes 指的是這些 properties 文件中排除test.properties 文件。
Nexus下載安裝及對接
maven jar包沖突解決方案、導入非maven工程jar包
總結
以上是生活随笔為你收集整理的maven pom.xml解析、命令说明、依赖传递、继承、聚合、properties、build、依赖范围、版本仲裁、profile的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot整合elastics
- 下一篇: 车主因眼睛小被自动驾驶误判?——智能座舱