📢 本文由 gemini-3-flash-preview 翻譯
Maven 是一款用於管理和建置 Java 專案的工具
Maven 可以方便快捷地管理專案相依的資源 (Jar 檔),避免版本衝突問題;提供標準、統一的專案結構;標準跨平台的自動化專案建置方式
安裝
在
官網
下載後解壓,然後設定本地存放庫,修改 conf/setting.xml 中的 <localRepository> 為一個指定目錄
1
2
| <!-- 例如本地庫在 D:\develop\maven_repo -->
<localRepository>D:\develop\maven_repo</localRepository>
|
設定阿里雲私服鏡像,修改 conf/setting.xml 中的 <mirror> 標籤,新增子標籤
1
2
3
4
5
6
| <mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
|
設定環境變數:MAVEN_HOME 為 Maven 解壓目錄,並將其 bin 目錄加入 PATH 環境變數
測試安裝完成:在命令列輸入 mvn -v 查看輸出
相依性配置
相依性 (Dependency):指當前專案執行所需要的 Jar 檔,一個專案中可以引入多個相依性
設定步驟:
- 在 pom.xml 中編寫
<dependencies> 標籤 - 在
<dependencies> 標籤中使用 <dependency> 引入座標 - 定義座標的 groupId, artifactId, version
- 重新整理配置,引入新加入的座標
1
2
3
4
5
6
7
8
| <!-- 例如引入 logback -->
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
|
可以到
https://mvnrepository.com/
查找相依性座標資訊
相依性傳遞
相依性具有傳遞性
- 直接相依:在當前專案中透過相依性配置建立的相依關係
- 間接相依:被相依的資源如果相依於其他資源,則當前專案間接相依於其他資源
當新增相依性時,若此套件相依於其他套件,將自動新增相關套件
當然,若某個套件的子套件並不需要,可以排除相依 (指主動斷開相依的資源,被排除的資源無需指定版本)
1
2
3
4
5
6
7
8
9
10
11
12
| <!-- 例如排除某專案的 junit -->
<dependency>
<groupId>com.yexca</groupId>
<artifactId>maven-project</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
|
相依性範圍
相依的 Jar 檔,預設可以在任何地方使用,可以透過 <scope>...</scope> 設定其作用範圍:
- 主程式範圍有效 (main 資料夾範圍內)
- 測試程式範圍有效 (test 資料夾範圍內)
- 是否參與打包執行 (package 指令範圍內)
| scope 值 | 主程式 | 測試程式 | 打包 (執行) | 範例 |
|---|
| compile (預設) | Y | Y | Y | log4j |
| test | - | Y | - | junit |
| provided | Y | Y | - | servlet-api |
| runtime | - | Y | Y | JDBC 驅動 |
1
2
3
4
5
6
| <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
|
生命周期
Maven 的生命週期是為了對所有的 Maven 專案建置過程進行抽象和統一
Maven 中有 3 套相互獨立的生命週期:
- clean:清理工作
- default:核心工作,如:編譯、測試、打包、安裝、部署等
- site:生成報告、發布站台等
其中每套生命週期包含一些階段 (phase),階段是有順序的,後面的階段相依於前面的階段
clean
- pre-clean
- clean:移除上一次建置產生的檔案 (target 資料夾)
- post-clean
default
- validate
- initialize
- generate-sources
- process-sources
- generate-resources
- process-resources
- compile:編譯專案原始碼
- process-classes
- generate-test-sources
- process-test-sources
- generate-test-resources
- process-test-resources
- test-compile
- process-test-classes
- test:使用合適的單元測試框架執行測試 (JUnit)
- prepare-package
- package:將編譯後的檔案打包,如 Jar、War 等
- verify
- install:安裝專案到本地存放庫
- deploy
site
- pre-site
- site
- post-site
- site-deploy
在同一套生命週期中,當執行後面的階段時,前面的階段都會執行
分模組設計
分模組設計是在進行專案設計階段時,就可以將一個大型專案拆分成若干個模組,每一個模組都是獨立的,如果我們需要用到另外一個模組的功能,直接引用該模組的相依性即可
可以把一些通用的實體類別或工具類別單獨作為一個模組,若某一模組需要使用,直接引入對應的相依性即可
方便專案的管理維護、擴充,也方便模組間的相互呼叫與資源共享
繼承
像 Lombok 相依性,可能專案中的每個模組都會使用,每個模組都宣告一次相當繁瑣,可以透過繼承解決這個問題
繼承關係
建立一個父工程,將模組共有的相依性都提取到父工程進行配置,只要子類別繼承了父工程,相依性也會繼承下來,這樣就無需在各個子工程中進行配置了
繼承描述的是兩個工程間的關係,與 Java 中的繼承相似,子工程可以繼承父工程中的配置資訊,常見於相依關係的繼承,可以簡化相依性配置、統一管理相依性
1
2
3
4
5
6
7
| <!--指定父工程-->
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<relativePath>....</relativePath>
</parent>
|
如果是 JavaWeb 開發,可以讓父工程繼承 spring-boot-starter-parent,其他模組繼承該父工程
一般情況下,在檔案結構中,子工程為父工程的子目錄
以下為例子
- 父工程的打包方式為 pom
1
2
3
4
5
6
7
8
9
10
11
| <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.yexca</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
|
Maven 打包方式:
- jar:普通模組打包,SpringBoot 專案基本都是 Jar 檔 (內建 Tomcat 執行)
- war:普通 Web 程式打包,需要部署在外部的 Tomcat 伺服器中執行
- pom:父工程或聚合工程,該模組不寫程式碼,僅進行相依性管理
- 子工程指定父工程
1
2
3
4
5
6
7
8
9
10
11
12
13
| <parent>
<groupId>net.yexca</groupId>
<artifactId>tlias-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 指定父工程的 pom 檔案的相對位置 (如果不指定,將從本地存放庫/遠端存放庫查找該工程) -->
<relativePath>../tlias-parent/pom.xml</relativePath>
</parent>
<!-- <groupId>net.yexca</groupId>
- 因為自動繼承父工程,可以省略
-->
<artifactId>tlias-utils</artifactId>
<version>1.0-SNAPSHOT</version>
|
- 父工程中配置共有相依性
1
2
3
4
5
6
7
| <dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
|
版本鎖定
某些相依性部分模組需要,部分模組不需要,可以在父級中管理相依性的 version,方便管理與修改
可以透過 <dependencyManagement> 標籤管理相依性版本
父工程
1
2
3
4
5
6
7
8
9
10
11
| <!--統一管理相依性版本-->
<dependencyManagement>
<dependencies>
<!--JWT權杖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
</dependencyManagement>
|
子工程
1
2
3
4
5
6
7
8
9
10
| <dependencies>
<!--JWT權杖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<!-- <version>0.9.1</version>
- 因為父工程指定了版本,不需要填寫
-->
</dependency>
</dependencies>
|
父工程的 <dependencyManagement> 配置只管理版本,不會將相依性引入子工程。只有在子工程引入後才會生效,只是引入時無需指定版本號
而 <dependencies> 會把相依性直接引入所有子工程
屬性設定
也可以透過自定義屬性及屬性引用的形式,在父工程中將相依性的版本號進行集中管理維護
自定義屬性:
1
2
3
| <properties>
<lombok.version>1.18.24</lombok.version>
</properties>
|
引用屬性:
1
2
3
4
5
| <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
|
於是可以在父工程中將所有的版本號,集中管理維護
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
| <properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<lombok.version>1.18.24</lombok.version>
<jjwt.version>0.9.1</jjwt.version>
<aliyun.oss.version>3.15.1</aliyun.oss.version>
<jaxb.version>2.3.1</jaxb.version>
<activation.version>1.1.1</activation.version>
<jaxb.runtime.version>2.3.3</jaxb.runtime.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<!--統一管理相依性版本-->
<dependencyManagement>
<dependencies>
<!--JWT權杖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<!--阿里雲OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb.version}</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>${activation.version}</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>${jaxb.runtime.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
|
若想要修改相依性的版本,只需要在父工程的自定義屬性中,修改相應屬性值即可
聚合
若一個模組相依於另一個模組,打包該模組前需要先將其他模組 install 到本地存放庫,然後再打包。如果相依的模組很多,那麼需要執行的操作會過於繁瑣
透過 Maven 的聚合就可以輕鬆實現專案的一鍵建置 (清理、編譯、測試、打包、安裝等)
- **聚合:**將多個模組組織成一個整體,同時進行專案的建置
- **聚合工程:**一個不具有業務功能的「空」工程 (有且僅有一個 pom 檔案。一般來說,繼承關係中的父工程與聚合關係中的聚合工程是同一個)
- **作用:**快速建置專案 (無需根據相依關係手動建置,直接在聚合工程上建置即可)
可以在聚合工程中透過 <modules> 設定當前聚合工程所包含的子模組名稱
1
2
3
4
5
6
7
| <!--聚合其他模組-->
<modules>
<!-- 工程路徑 -->
<module>../tlias-pojo</module>
<module>../tlias-utils</module>
<module>../tlias-web-management</module>
</modules>
|
之後進行編譯、打包、安裝操作只需在聚合工程上進行即可,其他工程會自動同步操作
| 繼承 | 聚合 |
|---|
| 作用 | 繼承用於簡化相依性配置、統一管理相依性 | 聚合用於快速建置專案 |
| 相同點 | 打包方式均為 pom,通常製作在同一個 pom | 均屬於設計型模組,無實際內容 |
| 不同點 | 繼承是在子模組中配置關係 父模組無法感知哪些子模組繼承了自己 | 聚合是在聚合工程中配置關係 聚合可以感知到參與聚合的模組有哪些 |
私服
私服是一種特殊的遠端存放庫,它是架設在區域網路內的存放庫服務,用來代理位於外部的中央存放庫,用於解決團隊內部的資源共享與資源同步問題
如果在專案中需要使用其他第三方提供的相依性,如果本地存放庫沒有,會自動連接私服下載,如果私服也沒有,私服此時會自動連接中央存放庫,去中央存放庫中下載相依性,然後將下載的相依性儲存在私服存放庫及本地存放庫中
私服一般一個公司一台,不用自己配置
私服存放庫與專案版本
私服存放庫說明:
- RELEASE:儲存自己開發的 RELEASE 發布版本的資源
- SNAPSHOT:儲存自己開發的 SNAPSHOT 發布版本的資源
- Central:儲存的是從中央存放庫下載下來的相依性
專案版本說明:
- RELEASE (發布版本):功能趨於穩定、當前更新停止,可以用於發行的版本,儲存在私服中的 RELEASE 存放庫中
- SNAPSHOT (快照版本):功能不穩定、尚處於開發中的版本,即快照版本,儲存在私服的 SNAPSHOT 存放庫中
設定
設定私服的存取使用者名稱與密碼,在 Maven 安裝目錄的 conf/settings.xml 的 servers 配置中設定
1
2
3
4
5
6
7
8
9
10
11
12
13
| <servers>
<server>
<id>maven-releases</id>
<username>admin</username>
<password>admin</password>
</server>
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>admin</password>
</server>
</servers>
|
設定私服相依性下載的存放庫群組地址,檔案同上,修改 mirrors 與 profiles 標籤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| <mirrors>
<mirror>
<id>maven-public</id>
<mirrorOf>*</mirrorOf>
<url>http://127.0.0.1:8081/repository/maven-public/</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>allow-snapshots</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>maven-public</id>
<url>http://127.0.0.1:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
|
pom 檔案設定上傳地址,在父工程中設定即可
1
2
3
4
5
6
7
8
9
10
11
12
13
| <distributionManagement>
<!-- release 版本的發布地址 -->
<repository>
<id>maven-releases</id>
<url>http://127.0.0.1:8081/repository/maven-releases/</url>
</repository>
<!-- snapshot 版本的發布地址 -->
<snapshotRepository>
<id>maven-snapshots</id>
<url>http://127.0.0.1:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
|
設定完成後,執行父工程的 deploy 生命周期即可將專案發布到私服存放庫