Maven 學習

📢 本文由 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 檔,一個專案中可以引入多個相依性

設定步驟:

  1. 在 pom.xml 中編寫 <dependencies> 標籤
  2. <dependencies> 標籤中使用 <dependency> 引入座標
  3. 定義座標的 groupId, artifactId, version
  4. 重新整理配置,引入新加入的座標
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 (預設)YYYlog4j
test-Y-junit
providedYY-servlet-api
runtime-YYJDBC 驅動
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,其他模組繼承該父工程

一般情況下,在檔案結構中,子工程為父工程的子目錄

以下為例子

  1. 父工程的打包方式為 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. 子工程指定父工程
 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. 父工程中配置共有相依性
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 生命周期即可將專案發布到私服存放庫