《Maven 基礎教程》系列,包含以下 3 篇文章:
- Maven 基礎教程(一):基礎介紹、開發環境配置
- Maven 基礎教程(二):Maven 的使用
- Maven 基礎教程(三):build、profile
😊 如果您覺得這篇文章有用 ?? 的話,請給博主一個一鍵三連 🚀🚀🚀 吧 (點贊 🧡、關注 💛、收藏 💚)!!!您的支持 💖💖💖 將激勵 🔥 博主輸出更多優質內容!!!
Maven 基礎教程(三):build、profile
- 4.build 標簽
- 4.1 build 標簽的組成
- 4.1.1 定義約定的目錄結構
- 4.1.2 備用插件管理
- 4.1.3 生命周期插件
- 4.2 典型應用:指定 JDK 版本
- 4.3 典型應用:SpringBoot 定制化打包
- 5. 依賴配置補充
- 5.1 import
- 5.2 system
- 5.3 runtime
- 6.profile
- 6.1 profile 概述
- 6.2 profile 配置
- 6.2.1 外部視角:配置文件
- 6.2.2 內部實現:具體標簽
- 6.3 激活 profile
- 6.4 Maven profile 多環境管理
4.build 標簽
在實際使用 Maven 的過程中,我們會發現 build
標簽有時候有,有時候沒,這是怎么回事呢?其實通過有效 POM 我們能夠看到,build
標簽的相關配置其實一直都在,只是在我們需要定制構建過程的時候才會通過配置 build
標簽覆蓋默認值或補充配置。這一點我們可以通過打印有效 POM 來看到。
打印有效 pom
mvn help:effective-pom
當默認配置無法滿足需求的定制構建的時候,就需要使用 build
標簽。
4.1 build 標簽的組成
build
標簽的子標簽大致包含三個主體部分:
- 1?? 定義約定的目錄結構
- 2?? 備用插件管理
- 3?? 生命周期插件
4.1.1 定義約定的目錄結構
<sourceDirectory>D:\product\maven-demo-parent\demo-module\src\main\java</sourceDirectory>
<scriptSourceDirectory>D:\product\maven-demo-parent\demo-module\src\main\scripts</scriptSourceDirectory>
<testSourceDirectory>D:\product\maven-demo-parent\demo-module\src\test\java</testSourceDirectory>
<outputDirectory>D:\product\maven-demo-parent\demo-module\target\classes</outputDirectory>
<testOutputDirectory>D:\product\maven-demo-parent\demo-module\target\test-classes</testOutputDirectory>
<resources><resource><directory>D:\product\maven-demo-parent\demo-module\src\main\resources</directory></resource>
</resources>
<testResources><testResource><directory>D:\product\maven-demo-parent\demo-module\src\test\resources</directory></testResource>
</testResources>
<directory>D:\product\maven-demo-parent\demo-module\target</directory>
<finalName>demo-module-1.0-SNAPSHOT</finalName>
各個目錄的作用如下:
目錄名 | 作用 |
---|---|
sourceDirectory | 主體源程序存放目錄 |
scriptSourceDirectory | 腳本源程序存放目錄 |
testSourceDirectory | 測試源程序存放目錄 |
outputDirectory | 主體源程序編譯結果輸出目錄 |
testOutputDirectory | 測試源程序編譯結果輸出目錄 |
resources | 主體資源文件存放目錄 |
testResources | 測試資源文件存放目錄 |
directory | 構建結果輸出目錄 |
4.1.2 備用插件管理
pluginManagement
標簽存放著幾個極少用到的插件:
- maven-antrun-plugin
- maven-assembly-plugin
- maven-dependency-plugin
- maven-release-plugin
通過 pluginManagement
標簽管理起來的插件就像 dependencyManagement
一樣,子工程使用時可以省略版本號,起到在父工程中統一管理版本的效果。
4.1.3 生命周期插件
plugins
標簽存放的是默認生命周期中實際會用到的插件,這些插件想必大家都不陌生,所以拋開插件本身不談,plugin
標簽的結構如下:
<plugin><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><executions><execution><id>default-compile</id><phase>compile</phase><goals><goal>compile</goal></goals></execution><execution><id>default-testCompile</id><phase>test-compile</phase><goals><goal>testCompile</goal></goals></execution></executions>
</plugin>
坐標部分
artifactId
和version
標簽定義了插件的坐標,作為 Maven 的自帶插件這里省略了groupId
。
執行部分
executions
標簽內可以配置多個execution
標簽,execution
標簽內:id
:指定唯一標識phase
:關聯的生命周期階段goals
/goal
:關聯指定生命周期的目標。goals
標簽中可以配置多個goal
標簽,表示一個生命周期環節可以對應當前插件的多個目標。
4.2 典型應用:指定 JDK 版本
前面我們在 settings.xml
中配置了 JDK 版本,那么將來把 Maven 工程部署都服務器上,脫離了 settings.xml
配置,如何保證程序正常運行呢?思路就是我們直接把 JDK 版本信息告訴負責編譯操作的 maven-compiler-plugin
插件,讓它在構建過程中,按照我們指定的信息工作。如下:
<!-- build 標簽:意思是告訴 Maven,你的構建行為,我要開始定制了!-->
<build><!-- plugins 標簽:Maven 你給我聽好了,你給我構建的時候要用到這些插件!--><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>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin></plugins>
</build>
settings.xml
中配置:僅在本地生效,如果脫離當前settings.xml
能夠覆蓋的范圍,則無法生效。- 在當前 Maven 工程
pom.xml
中配置:無論在哪個環境執行編譯等構建操作都有效。
4.3 典型應用:SpringBoot 定制化打包
很顯然 spring-boot-maven-plugin
并不是 Maven 自帶的插件,而是 SpringBoot 提供的,用來改變 Maven 默認的構建行為。具體來說是改變打包的行為。默認情況下 Maven 調用 maven-jar-plugin
插件的 jar
目標,生成普通的 jar
包。
普通 jar
包沒法使用 java -jar xxx.jar
這樣的命令來啟動、運行,但是 SpringBoot 的設計理念就是每一個 微服務 導出為一個 jar
包,這個 jar
包可以使用 java -jar xxx.jar
這樣的命令直接啟動運行。
這樣一來,打包的方式肯定要進行調整。所以 SpringBoot 提供了 spring-boot-maven-plugin
這個插件來定制打包行為。
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.5.5</version></plugin></plugins>
</build>
5. 依賴配置補充
管理依賴最基本的辦法是繼承父工程,但是和 Java 類一樣,Maven 也是單繼承的。如果不同體系的依賴信息封裝在不同 POM 中了,沒辦法繼承多個父工程怎么辦?這時就可以使用 import
依賴范圍。
5.1 import
典型案例當然是在項目中引入 SpringBoot、SpringCloud 依賴:
<dependencyManagement><dependencies><!-- SpringCloud 微服務 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringCloud Alibaba 微服務 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
import
依賴范圍使用要求:
- 打包類型必須是
pom
- 必須放在
dependencyManagement
中
官網說明如下:
This scope is only supported on a dependency of type pom in the section. It indicates the dependency is to be replaced with the effective list of dependencies in the specified POM’s section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.
5.2 system
以 Windows 系統環境下開發為例,假設現在 D:\product\maven-demo-parent\demo-module\target\demo-module-1.0-SNAPSHOT.jar
想要引入到我們的項目中,此時我們就可以將依賴配置為 system
范圍:
<dependency><groupId>net.javatv.maven</groupId><artifactId>demo-module</artifactId><version>1.0-SNAPSHOT</version><systemPath>D:\product\maven-demo-parent\demo-module\target\demo-module-1.0-SNAPSHOT.jar</systemPath><scope>system</scope>
</dependency>
但是很明顯:這樣引入依賴完全不具有可移植性,所以不要使用。
5.3 runtime
專門用于編譯時不需要,但是運行時需要的 jar
包。比如:編譯時我們根據接口調用方法,但是實際運行時需要的是接口的實現類。典型案例是:
<!--熱部署 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional>
</dependency>
6.profile
6.1 profile 概述
這里我們可以對接 profile
這個單詞中 側面 這個含義:項目的每一個運行環境,相當于是項目整體的一個側面。
通常情況下,我們項目至少有三種運行環境:
- 開發環境:供不同開發工程師開發的各個模塊之間互相調用、訪問;內部使用。
- 測試環境:供測試工程師對項目的各個模塊進行功能測試;內部使用。
- 生產環境:供最終用戶訪問,所以這是正式的運行環境,對外提供服務。
我們這里的 環境 仍然只是一個籠統的說法,實際工作中一整套運行環境會包含很多種不同服務器:
- MySQL
- Redis
- ElasticSearch
- RabbitMQ
- FastDFS
- Nginx
- Tomcat
- ……
就拿其中的 MySQL 來說,不同環境下的訪問參數肯定完全不同,可是代碼只有一套。如果在 jdbc.properties
里面來回改,那就太麻煩了,而且很容易遺漏或寫錯,增加調試的難度和工作量。所以最好的辦法就是把適用于各種不同環境的配置信息分別準備好,部署哪個環境就激活哪個配置。
在 Maven 中,使用 profile
機制來管理不同環境下的配置信息。但是解決同類問題的類似機制在其他框架中也有,而且從模塊劃分的角度來說,持久化層的信息放在構建工具中配置也違反了 高內聚,低耦合 的原則。
實際上,即使我們在 pom.xml
中不配置 profile
標簽,也已經用到 profile
了。為什么呢?因為根標簽 project
下所有標簽相當于都是在設定默認的 profile
。這樣一來我們也就很容易理解下面這句話:project
標簽下除了 modelVersion
和坐標標簽之外,其它標簽都可以配置到 profile
中。
6.2 profile 配置
6.2.1 外部視角:配置文件
從外部視角來看,profile
可以在下面兩種配置文件中配置:
settings.xml
:全局生效。其中我們最熟悉的就是配置 JDK 1.8。pom.xml
:當前 POM 生效。
6.2.2 內部實現:具體標簽
從內部視角來看,配置 profile
有如下語法要求:
1?? profiles
/ profile
標簽
- 由于
profile
天然代表眾多可選配置中的一個,所以由復數形式的profiles
標簽統一管理。 - 由于
profile
標簽覆蓋了pom.xml
中的默認配置,所以profiles
標簽通常是pom.xml
中的最后一個標簽。
2?? id
標簽
每個 profile
都必須有一個 id
標簽,指定該 profile
的唯一標識。這個 id
標簽的值會在命令行調用 profile
時被用到。這個命令格式是:
-D<profile id>
3?? 其它允許出現的標簽
一個 profile
可以覆蓋項目的 最終名稱、項目依賴、插件配置 等各個方面以影響構建行為。
build
defaultGoal
finalName
resources
testResources
plugins
reporting
modules
dependencies
dependencyManagement
repositories
pluginRepositories
properties
6.3 激活 profile
1?? 默認配置默認被激活
前面提到了,POM 中沒有在 profile
標簽里的就是默認的 profile
,當然默認被激活。
2?? 基于環境信息激活
環境信息包含:JDK 版本、操作系統參數、文件、屬性 等各個方面。一個 profile
一旦被激活,那么它定義的所有配置都會覆蓋原來 POM 中對應層次的元素。可參考下面的標簽結構:
<profile><id>dev</id><activation><!-- 配置是否默認激活 --><activeByDefault>false</activeByDefault><jdk>1.5</jdk><os><name>Windows XP</name><family>Windows</family><arch>x86</arch><version>5.1.2600</version></os><property><name>mavenVersion</name><value>2.0.5</value></property><file><exists>file2.properties</exists><missing>file1.properties</missing></file></activation>
</profile>
這里有個問題是:多個激活條件之間是什么關系呢?
- Maven
3.2.2
之前:遇到第一個滿足的條件即可激活,或的關系。 - Maven
3.2.2
開始:各條件均需滿足,且的關系。
下面我們來看一個具體例子。假設有如下 profile
配置,在 JDK 版本為 1.6
時被激活:
<profiles><profile><id>JDK1.6</id><activation><!-- 指定激活條件為:JDK 1.6 --><jdk>1.6</jdk></activation>……</profile>
</profiles>
這里需要指出的是:Maven 會自動檢測當前環境安裝的 JDK 版本,只要 JDK 版本是以 1.6
開頭都算符合條件。下面幾個例子都符合:
1.6.0_03
1.6.0_02
- ……
6.4 Maven profile 多環境管理
在開發過程中,我們的軟件會面對不同的運行環境,比如開發環境、測試環境、生產環境,而我們的軟件在不同的環境中,有的配置可能會不一樣,比如數據源配置、日志文件配置、以及一些軟件運行過程中的基本配置,那每次我們將軟件部署到不同的環境時,都需要修改相應的配置文件,這樣來回修改,很容易出錯,而且浪費勞動力。
因此我們可以利用 Maven 的 profile
來進行定義多個 profile
,然后每個 profile
對應不同的激活條件和配置信息,從而達到不同環境使用不同配置信息的效果。
<build><!-- profile對資源的操作 --><resources><resource><directory>src/main/resources</directory><!-- 先排除所有環境相關的配置文件 --><excludes><exclude>application*.yml</exclude></excludes></resource><resource><directory>src/main/resources</directory><!-- 是否替換 @xx@ 表示的maven properties屬性值 --><!--通過開啟 filtering,maven 會將文件中的 @xx@ 替換 profile 中定義的 xx 變量/屬性--><filtering>true</filtering><includes><include>application.yml</include><include>application-${profileActive}.yml</include></includes></resource></resources>
</build><!--多環境文件配置-->
<profiles><!--開發環境--><profile><id>dev</id><activation><!--默認激活--><activeByDefault>true</activeByDefault></activation><properties><profileActive>dev</profileActive></properties></profile><!--測試環境--><profile><id>test</id><properties><profileActive>test</profileActive></properties></profile><!--正式環境--><profile><id>prod</id><properties><profileActive>prod</profileActive></properties></profile>
</profiles>
在 idea
中可以看到,因此,當你需要打包哪一個環境的就勾選即可:
同時,SpringBoot 天然支持多環境配置,一般來說,application.yml
存放公共的配置,application-dev.yml
、application-test.yml
、application.prod.yml
分別存放三個環境的配置。如下:
application.yml
中配置 spring.profiles.active=prod
(或者 dev
、test
)指定使用的配置文件,如下:
注:profileActive
,就是上面我們自定義的標簽。
然后當我們勾選哪一個環境,打包的配置文件就是那一個環境:
同時我們再在 resource
標簽下看到 includes
和 excludes
標簽。它們的作用是:
includes
:指定執行resource
階段時要包含到目標位置的資源。excludes
:指定執行resource
階段時要排除的資源。