《Maven 基礎教程》系列,包含以下 2 篇文章:
- Maven 基礎教程(一):基礎介紹、開發環境配置
- Maven 基礎教程(二):Maven 的使用
😊 如果您覺得這篇文章有用 ?? 的話,請給博主一個一鍵三連 🚀🚀🚀 吧 (點贊 🧡、關注 💛、收藏 💚)!!!您的支持 💖💖💖 將激勵 🔥 博主輸出更多優質內容!!!
Maven 基礎教程(二):Maven 的使用
- 3.Maven 的使用
- 3.1 核心概念:坐標
- 3.2 pom.xml
- 3.3 依賴
- 3.4 依賴的傳遞
- 3.5 依賴的排除
- 3.6 繼承
- 3.6.1 概念
- 3.6.2 作用
- 3.6.3 一個例子
- 3.7 聚合
- 3.7.1 Maven 中的聚合
- 3.7.2 繼承和聚合的對應關系
- 3.7.3 聚合的配置
- 3.7.4 依賴循環問題
3.Maven 的使用
3.1 核心概念:坐標
數學中的坐標使用 x x x、 y y y、 z z z 三個 向量 作為空間的坐標系,可以在 空間 中唯一的定位到一個 點。
Maven 中的坐標使用三個 向量 在 Maven的倉庫 中唯一的定位到一個 jar 包。
groupId
:公司或組織的id
,即公司或組織域名的 倒序,通常也會加上項目名稱。例如:com.javatv.maven
。artifactId
:一個項目或者是項目中的一個模塊的id
,即模塊的名稱,將來作為 Maven 工程的工程名。例如:auth
。version
:版本號。例如:1.0.0
。
坐標和倉庫中 jar
包的存儲路徑之間的對應關系,如下:
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
上面坐標對應的 jar
包在 Maven 本地倉庫中的位置:
Maven本地倉庫根目錄\javax\servlet\servlet-api\2.5\servlet-api-2.5.jar
3.2 pom.xml
POM
:Project Object Model
,項目對象模型。和POM
類似的是DOM
(Document Object Model
),文檔對象模型。它們都是模型化思想的具體體現。POM
表示將工程抽象為一個模型,再用程序中的對象來描述這個模型。這樣我們就可以用程序來管理項目了。我們在開發過程中,最基本的做法就是將現實生活中的事物抽象為模型,然后封裝模型相關的數據作為一個對象,這樣就可以在程序中計算與現實事物相關的數據。POM
理念集中體現在 Maven 工程根目錄下pom.xml
這個配置文件中。所以這個pom.xml
配置文件就是 Maven 工程的 核心配置文件。其實學習 Maven 就是學這個文件怎么配置,各個配置有什么用。
<!-- 當前Maven工程的坐標 -->
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<!-- 當前Maven工程的打包方式,可選值有下面三種:-->
<!-- jar:表示這個工程是一個Java工程 -->
<!-- war:表示這個工程是一個Web工程 -->
<!-- pom:表示這個工程是“管理其他工程”的工程 -->
<packaging>jar</packaging><properties><!-- 工程構建過程中讀取源碼時使用的字符集 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties><!-- 當前工程所依賴的jar包 -->
<dependencies><!-- 使用dependency配置一個具體的依賴 --><dependency><!-- 在dependency標簽內使用具體的坐標依賴我們需要的一個jar包 --><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><!-- scope標簽配置依賴的范圍 --><scope>test</scope></dependency>
</dependencies>
3.3 依賴
上面說到我們使用 Maven 最主要的就是使用它的依賴管理功能,引入依賴存在一個范圍,Maven 的依賴范圍包括:compile
,provided
,runtime
,test
,system
。
compile
:表示編譯范圍,指 A 在編譯時依賴 B,該范圍為默認依賴范圍。編譯范圍的依賴會用在編譯,測試,運行,由于運行時需要,所以編譯范圍的依賴會被打包。provided
:provied
依賴只有當jdk
或者一個容器已提供該依賴之后才使用。provided
依賴在編譯和測試時需要,在運行時不需要。例如:Servlet API 被 Tomcat 容器提供了。runtime
:runtime
依賴在運行和測試系統時需要,但在編譯時不需要。例如:JDBC 的驅動包。由于運行時需要,所以runtime
范圍的依賴會被打包。test
:test
范圍依賴在編譯和運行時都不需要,只在測試編譯和測試運行時需要。例如:Junit。由于運行時不需要,所以test
范圍依賴不會被打包。system
:system
范圍依賴與provided
類似,但是必須顯示的提供一個對于本地系統中jar
文件的路徑。一般不推薦使用。
依賴范圍 | 編譯 | 測試 | 運行時 | 是否會被打入 jar 包 |
---|---|---|---|---|
compile | ? | ? | ? | ? |
provided | ? | ? | ? | ? |
runtime | ? | ? | ? | ? |
test | ? | ? | ? | ? |
system | ? | ? | ? | ? |
而在實際開發中,我們常用的就是 compile
、test
、provided
。
3.4 依賴的傳遞
A 依賴 B,B 依賴 C,那么在 A 沒有配置對 C 的依賴的情況下,A 里面能不能直接使用 C?在以上的前提下,C 是否能夠傳遞到 A,取決于 B 依賴 C 時使用的依賴范圍。B 依賴 C 時使用 compile
范圍:可以傳遞;B 依賴 C 時使用 test
或 provided
范圍:不能傳遞。所以需要這樣的 jar
包時,就必須在需要的地方明確配置依賴才可以。
3.5 依賴的排除
當 A 依賴 B,B 依賴 C,而且 C 可以傳遞到 A 的時候,A 不想要 C,需要在 A 里面把 C 排除掉。而往往這種情況都是為了避免 jar
包之間的沖突。
所以配置依賴的排除其實就是阻止某些 jar
包的傳遞。因為這樣的 jar
包傳遞過來會和其他 jar
包沖突。
一般通過使用 excludes
標簽配置依賴的排除:
<dependency><groupId>net.javatv.maven</groupId><artifactId>auth</artifactId><version>1.0.0</version><scope>compile</scope><!-- 使用excludes標簽配置依賴的排除 --><exclusions><!-- 在exclude標簽中配置一個具體的排除 --><exclusion><!-- 指定要排除的依賴的坐標(不需要寫version) --><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions></dependency>
3.6 繼承
3.6.1 概念
Maven 工程之間,A 工程繼承 B 工程
- B 工程:父工程
- A 工程:子工程
本質上是 A 工程的 pom.xml
中的配置繼承了 B 工程中 pom.xml
的配置。
3.6.2 作用
在父工程中統一管理項目中的依賴信息,具體來說是管理依賴信息的版本。
它的背景是:
- 對一個比較大型的項目進行了模塊拆分。
- 一個
project
下面,創建了很多個module
。 - 每一個
module
都需要配置自己的依賴信息。
它背后的需求是:
- 在每一個
module
中各自維護各自的依賴信息很容易發生出入,不易統一管理。 - 使用同一個框架內的不同
jar
包,它們應該是同一個版本,所以整個項目中使用的框架版本需要統一。 - 使用框架時所需要的
jar
包組合(或者說依賴信息組合)需要經過長期摸索和反復調試,最終確定一個可用組合。這個耗費很大精力總結出來的方案不應該在新的項目中重新摸索。 - 通過在父工程中為整個項目維護依賴信息的組合既保證了整個項目使用規范、準確的
jar
包;又能夠將以往的經驗沉淀下來,節約時間和精力。
3.6.3 一個例子
1?? 一般在模塊化開發中一般都會創建一個父工程,如下:
父工程創建好之后,要修改它的打包方式:
<!-- 當前工程作為父工程,它要去管理子工程,所以打包方式必須是 pom -->
<packaging>pom</packaging>
只有打包方式為 pom
的 Maven 工程能夠管理其他 Maven 工程。打包方式為 pom
的 Maven 工程中不寫業務代碼,它是專門管理其他 Maven 工程的工程,所以可以將生成的 src
目錄刪除。
2?? 創建模塊工程
然后可以在父工程的 pom
文件中看到:
而子工程的 pom
如下:
3?? 在父工程中配置依賴的統一管理
使用 dependencyManagement
標簽配置對依賴的管理,如下:
<?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>net.javatv.maven</groupId><artifactId>maven-demo-parent</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>demo-module</module></modules><dependencyManagement><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>5.3.19</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.19</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.19</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.3.19</version></dependency></dependencies></dependencyManagement></project>
而實際上被管理的依賴并沒有真正被引入到工程。
4?? 子工程中引用那些被父工程管理的依賴
關鍵點:省略版本號
子工程引用父工程中的依賴信息時,可以把版本號去掉。把版本號去掉就表示子工程中這個依賴的版本由父工程決定,具體來說是由父工程的 dependencyManagement
來決定。
子工程 pom
如下:
<?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標簽指定當前工程的父工程 --><parent><artifactId>maven-demo-parent</artifactId><groupId>net.javatv.maven</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><!-- 子工程的坐標 --><!-- 如果子工程坐標中的groupId和version與父工程一致,那么可以省略 --><artifactId>demo-module</artifactId><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId></dependency></dependencies></project>
此時,被管理的依賴才被引入到工程。
5?? 修改父工程依賴信息的版本
這個修改可以是降級,也可以是升級,但一般來說都是升級。
6?? 父工程中聲明自定義屬性
對同一個框架的一組 jar
包最好使用相同的版本,為了方便升級框架,可以將 jar
包的版本信息統一提取出來,統一聲明版本號:
<!-- 通過自定義屬性,統一指定Spring的版本 -->
<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 自定義標簽,維護Spring版本數據 --><spring.version>5.3.19</spring.version>
</properties>
在需要的地方使用 ${}
的形式來引用自定義的屬性名,真正實現一處修改,處處生效。
<?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>net.javatv.maven</groupId><artifactId>maven-demo-parent</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>demo-module</module></modules><!-- 通過自定義屬性,統一指定Spring的版本 --><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><!-- 自定義標簽,維護Spring版本數據 --><spring.version>5.3.19</spring.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency></dependencies></dependencyManagement></project>
編寫一套符合要求、開發各種功能都能正常工作的依賴組合并不容易。如果公司里已經有人總結了成熟的組合方案,那么再開發新項目時,如果不使用原有的積累,而是重新摸索,會浪費大量的時間。為了提高效率,我們可以使用工程繼承的機制,讓成熟的依賴組合方案能夠保留下來。如下:
如上圖所示,公司級的父工程中管理的就是成熟的依賴組合方案,各個新項目、子系統各取所需即可。
3.7 聚合
聚合,指分散的聚集到一起,即部分組成整體。
3.7.1 Maven 中的聚合
使用一個總工程將各個模塊工程匯集起來,作為一個整體對應完整的項目,實際就是 module
標簽。
- 項目:整體
- 模塊:部分
3.7.2 繼承和聚合的對應關系
從 繼承 關系角度來看:
- 父工程
- 子工程
從 聚合 關系角度來看:
- 總工程
- 模塊工程
3.7.3 聚合的配置
在總工程中配置 modules
即可:
<modules><module>demo-module</module>
</modules>
3.7.4 依賴循環問題
如果 A 工程依賴 B 工程,B 工程依賴 C 工程,C 工程又反過來依賴 A 工程,那么在執行構建操作時會報下面的錯誤:
DANGER[ERROR] [ERROR] The projects in the reactor contain a cyclic reference:
這個錯誤的含義是:循環引用。