前言
本文以當前最新發布版maven-3.6.3
爲例.酌情參考.
倉庫
得益於座標機制,任何Maven
項目使用任何一個構建的方式都是完全相同的。在此基礎上,Maven
可以在某個位置統一存儲所有Maven
項目共享的構件。這個統一的位置就是倉庫。實際的Maven
項目將不再各自存儲其依賴文件,它們只需要聲明這些依賴的座標,在需要的時候Maven
會自動根據座標找到相應的構件。
分類
Maven
倉庫的分類不能一概而論,根據不同的角度可以大致羅列如下:
位置分類
《Maven實戰》中將倉庫分爲:
本地倉庫主要起緩存作用,默認在~/.m2/repository
。
可以通過~/.m2/settings.xml
中的<localRepository>
修改。
發佈分類
根據是否發佈,可以分爲SNAPSHOT
和RELEASE
兩類。
性質分類
私服Nexus中將倉庫分類爲hosted
,group
和proxy
。
hosted
一般只包含SNAPSHOT
和RELEASE
兩類。因此Nexus內置了maven-snapshots
和maven-releases
。
group
顧名思義就是組,可以自由組合,類型不限。Nexus內置了maven-public
。
proxy
proxy
只能一次代理一個目標倉庫。一般都是將生成某一類proxy
地址歸併到一個group
中,形成類似Nginx
反向代理的效果。
proxy
類型應該是私服
用的最多的類型。
Nexus內置了maven-central
,它默認代理的是https://repo1.maven.org/maven2/。
結構
Maven
的目錄結構看起來比較簡單,包括:
├── bin
├── boot
├── conf
│ └── logging
└── lib
├── ext
└── jansi-native
├── freebsd32
├── freebsd64
├── linux32
├── linux64
├── osx
├── windows32
└── windows64
bin
bin主要存放命令行的執行腳本,包括mvn
和mvnDebug
。此外還有m2.conf
文件.這是classworlds
的配置文件.
boot
只有一個文件plexus-classworlds-x.x.x.jar
,是一個類加載器框架.一般不用關心.
conf
配置文件夾.包含最重要的settings.xml
.
lib
用以存放maven
運行時需要的Java
類庫.包含maven
自身及第三方依賴.
在當前版本3.6.3
中,該目錄下的maven-model-builder-3.6.3.jar
的org.maven.model
下存放了全局的pom-4.0.0.xml
,它定義了默認的central
倉庫鏈接:https://repo.maven.apache.org/maven2
.
座標
項目座標
指的是pom.xml
最外一層的xml
元素,常用的包括groupId
,artifactId
,version
,packaging
,dependencyManagement
和build
.
packaging
該元素定義Maven
項目的打包方式.首先,打包方式通常與所生成構件的文件擴展名稱對應.默認爲jar
,可供選類型包括但不限於jar
,war
,ear
和pom
.之所以不限是因爲打包插件可以自定義類型.
依賴座標
依賴座標是最最常用的元素了,這裏指對應pom.xml
中<dependency>
.
包括groupId
,artifactId
,version
,classifier
,type
和exclusions
.
type
一個依賴座標對應的文件格式一般爲$artifactId-$version-$classifier
,擴展名一般是$type
,它的默認值是jar
,不過儘管它通常表示依賴項文件名的擴展名,但並非總是如此。 可以將類型映射到其他擴展名和classifier
。 這種類型通常對應於所使用的包裝,儘管並非總是如此。 可供選項包括jar
,war
,ejb-client
和test-jar
。 可以通過將擴展名設置爲true
的插件來自定義新類型,因此這不是完整列表。
classifier
幫助定義構件輸出的一些附屬構件.比如文檔和源代碼.對應的classifier
就分別是javadoc
和sources
.
另外,常用的選項還有pom
,通常表示一些父依賴.
比較經典的應用是net.sf.json-lib:json-lib
,必須指定classifier
纔可正常工作.
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
注意:
不能直接定義項目的
classifier
因爲附屬構件不是項目直接默認生成的,而是由附加的插件幫助生成.
scope
依賴範圍:
依賴範圍 | 編譯 | 測試 | 運行 | 例子 |
---|---|---|---|---|
compile |
Y | Y | Y | spring-core |
test |
- | Y | - | Junit |
provided |
Y | Y | - | servlet-api |
runtime |
- | Y | Y | oracle-jdbc驅動 |
system |
Y | Y | - | 本地的,Maven倉庫之外的類庫文件 與 <systemPath> 搭配使用 |
配置文件
$MAVEN_HOME/conf/settings.xml
是全局配置文件。一般不建議修改。
當我們初次執行操作,如mvn help:system
時會創建~/.m2
和repository
目錄,同時生成空的settings.xml
用以存放用戶級別的配置。用戶根據需要修改~/.m2/settings.xml
。
<settings>
<!-- 本地倉庫位置,默認路徑: ${user.home}/.m2/repository -->
<localRepository>/path/to/local/repo</localRepository>
<!-- 交互模式,默認開啓 -->
<interactiveMode>true</interactiveMode>
<!-- 離線模式,默認關閉-->
<offline>false</offline>
<!-- 插件組-->
<pluginGroups> </pluginGroups>
<!-- 代理-->
<proxies></proxies>
<!-- 認證 -->
<servers></servers>
<!-- 鏡像-->
<mirrors> </mirrors>
<!-- 環境 -->
<profiles> </profiles>
<activeProfiles> </activeProfiles>
</settings>
localRepository
用以指定本地倉庫位置.
pluginGroups
當插件的組織Id(groupId)
沒有顯式提供時,供搜尋插件組織Id(groupId)
的列表。該元素包含一個pluginGroup
元素列表,每個子元素包含了一個組織Id(groupId)
。當我們使用某個插件,並且沒有在命令行爲其提供組織Id(groupId)
的時候,Maven
就會使用該列表。默認情況下該列表包含了org.apache.maven.plugins
和org.codehaus.mojo
.
proxy
有時候所在公司基於安全考慮,要求使用通過安全認證的代理訪問互聯網.這時候就需要爲其配置HTTP
代理,才能正常訪問和下載.可供配置標籤:
<proxies>
<proxy>
<!-- 可選 -->
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<username>proxyuser</username>
<password>proxypass</password>
<host>proxy.host.net</host>
<port>80</port>
<nonProxyHosts>local.net|some.host.com</nonProxyHosts>
</proxy>
</proxies>
proxies
下可以有多個proxy
元素,如果聲明瞭多個,則默認情況下第一個被激活的會生效.
nonProxyHosts
用來指定哪些主機不需要被代理.可以使用|
符號來分隔多個,同時支持通配符*
,比如*.aliyun.com
.
servers
用來配置遠程倉庫的認證信息,其中server
的id
與pom.xml
中的repository
的id
一一對應.
<servers>
<server>
<id>swb</id>
<username>admin</username>
<password>XXXX</password>
<privateKey>~/.ssh/id_rsa</privateKey>
<!--私鑰密碼-->
<passphrase>XXX</passphrase>
</server>
</servers>
profiles
類似springboot
中的profile
,針對不同的環境開啓不同的配置,比如在settings.xml
中設置統一的默認編譯版本:
<profiles>
<profile>
<id>java8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
<profile>
<id>java9</id>
<activation>
<activeByDefault>false</activeByDefault>
<jdk>9</jdk>
</activation>
<properties>
<maven.compiler.source>9</maven.compiler.source>
<maven.compiler.target>9</maven.compiler.target>
<maven.compiler.compilerVersion>9</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>java8</activeProfile>
<!-- <activeProfile>java9</activeProfile>-->
</activeProfiles>
除此之外,還可以通過命令行-P
參數指定:mvn compile -Pjava8
.
pom.xml
就像make
的Makefile
,Ant
的build.xml
一樣,pom.xml
是Maven
項目的核心.
<?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.example</groupId>
<artifactId>maven</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies></dependencies>
</project>
repositories
有些情況下,默認的中央倉庫無法滿足項目的需求,可能項目需要的構件存在於另外一個遠程倉庫中,如JBoss Maven
.這時,可以在POM
中配置該倉庫.
在repositories
元素下,可以使用repository
子元素聲明一個或者多個遠程倉庫.比如在超級POM
(位於maven-model-builder-3.6.3.jar
)中默認的倉庫配置:
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
使用的id
是central
,如果其他倉庫聲明的id
也一樣,就會覆蓋中央倉庫的配置.
這裏的snapshots
比較重要,定義了是否提供快照版本下載支持.對應的還有releases
,它們都是對應的xsd
規定的RepositoryPolicy
類型,默認爲真.
RepositoryPolicy
還包括updatePolicy
和checksumPolicy
,表示更新頻率和文件校驗策略.
updatePolicy
默認的值是daily
,表示每天檢查一次.其他可用的值包括:
never
-從不檢查更新always
-每次構建都檢查更新interval: X
-每隔X分鐘就檢查一次更新,X爲任意整數.
checksumPolicy
warn
,默認值,校驗不通過給出提示ignore
,忽略fail
,校驗不通過構建失敗.
layout
表示佈局,兩個可選項:legacy
和default
.
legacy
對應的是maven1
的佈局,一般不用.
default
對應的是maven2
和maven3
的佈局,是目前來說最常用的,因此也是默認值.
認證
有時出於安全考慮,需要認證後提供下載和部署服務,比如很多公司內部的私服不允許匿名拉取文件的.
但認證信息在settings.xml
中servers
的子元素server
中配置,通過id
與此處的repository
的id
一一對應.
其他Maven配置
除了全局的settings.xml
和項目級別pom.xml
,還有其他一些配置,比如MAVEN_OPTS
,項目根目錄下的.mvn
文件夾.具體參考官網configure
生命週期
Maven
擁有三套相互獨立的生命週期:clean
,default
和site
.
每個生命週期都包含多個階段(phase
),這些階段是有順序的.
clean
目的是清理項目,包含三個階段:.
階段 | 可執行 |
---|---|
pre-clean |
F |
clean |
T |
post-clean |
F |
default
定義了真正構件時所需要執行的所有步驟,它是所有生命週期中最核心的部分.它包含的階段較多,這裏僅僅列舉一些關鍵階段,它們均可在命令行顯式執行:
validate
驗證項目是否正確並且所有必要的信息均可用compile
test
package
verify
對集成測試的結果進行任何檢查,以確保符合質量標準install
將生成的包安裝到本地存儲庫中,以作爲本地其他項目中的依賴項deploy
在構建環境中完成後,將最終程序包部署到遠程存儲庫,以便與其他開發人員和項目共享。
site
目的是建立和發佈項目站點,Maven
能夠基於POM
所包含的信息,執行mvn site
命令會自動生成一個友好的站點,位於target/site
目錄下的靜態頁面,包含如下階段:
pre-site
site
post-site
site-deploy
將生成的項目站點發布到服務器上
本生命週期不常用,用到再補充.
插件
爲了達到開箱即用的效果,Maven
內置了許多常用插件:
name | phase | more details |
maven-clean-plugin | clean | clean_Lifecycle |
maven-resources-plugin | default | default-bindings |
maven-compiler-plugin | ||
maven-surefire-plugin | ||
maven-jar-plugin | ||
maven-install-plugin | ||
maven-deploy-plugin | ||
maven-site-plugin | site | site_Lifecycle |
插件目標
Maven
的核心僅僅定義了抽象的生命週期,具體的任務是交給插件完成的,插件爲了功能複用,又將其分爲多個目標.
比如maven-compiler-plugin
包含三個目標:
Goal | Description |
---|---|
compiler:compile | 綁定到編譯階段,用於編譯主要源文件。 |
compiler:help | 在maven-compiler-plugin 上顯示幫助信息。 調用mvn compiler:help -Ddetail=true -Dgoal=<goal-name> 以顯示參數詳細信息。 |
compiler:testCompile | 綁定到測試編譯階段,用於編譯測試源文件。 |
如果想查看其他插件目標,直接訪問官網,找到想了解的插件,查看:
插件綁定
Maven
的生命週期與插件相互綁定,用以完成實際的構建任務.
具體而言,是生命週期的階段與插件目標相互綁定.
內置綁定
爲了讓用戶幾乎不用任何配置就能構建Maven
項目,所以內置了一些綁定,官網中給出了一系列對應關係.
其中clean
和site
階段的綁定關係比較簡單,直接列舉出來了,default
階段的默認綁定比較複雜,是根據打包類型對應的,可以查看其給出的default-bindings.
POM配置
Maven
幫我們內置了一些插件,一般足夠滿足我們的需求,只有在很少的情況下,項目使用的插件無法在中央倉庫找到,或者自己編寫了插件,就必須考慮配置其他的遠程插件倉庫了.
pom.xml
爲我們提供了條件:
使用pluginRepositories
+pluginRepository
,其他配置則與repositories
+repository
相同.
命令行
命令行可以直接激活生命週期階段,也可以調用插件目標.
生命週期調用
mvn clean
mvn test
mvn clean install
mvn clean deploy site-deploy
插件目標調用
有些任務不適合綁定在生命週期上,所以Maven
提供了調用插件目標的方式:
mvn help:describe -Dplugin=compiler -Ddetail
mvn dependency:tree
describe
是插件目標沒錯,那help
是什麼呢,其實它是目標前綴,是Maven
爲了簡化調用而設定的.它的完整命令是:
mvn org.apache.maven.plugins:maven-help-plugin:3.2.0:describe -Dplugin=compiler -Ddetail
其中版本號可選.第二條命令同理.
插件前綴
一般的前綴與它的插件名稱對應:maven-XXX-plugin
,如果不一樣的話,以groupId
爲org.apache.maven.plugins
的官方插件爲例,可以通過遠程倉庫的maven-metadata.xml
查看所有插件的前綴.
聚合與繼承
聚合
對於複雜的Maven
項目,一般建議採用多模塊的方式來設計開發,便於後期維護管理。但是構建項目時,如果每次都需要按模塊一個一個進行構建會十分麻煩,而Maven
的聚合功能就可以很好的解決這個問題,當用戶對聚合模塊執行構建任務時,會對所有被其聚合的模塊自動地依次進行構建任務.
一個聚合項目,其packaging
必須定義爲pom
.然後使用modules
列舉其他模塊.
繼承
父
父模塊packaging
必須爲pom
.
主要涉及的元素是properties
,dependencyManagement
和pluginManagement
.
properties
預置屬性,子模塊可以直接使用.
dependencyManagement
定義一些可能涉及的不衝突的依賴,子模塊在使用相同的依賴時,可以忽略版本,防止衝突.
子模塊可以選擇不使用,顯式配置依賴時纔會生效.
當子模塊定義了不同的版本時,會覆蓋.
pluginManagement
與dependencyManagement
起相同作用.
公共依賴
如果有公共依賴,可以提取到這裏,以便統一管理.
可繼承元素
上述properties
,dependencyManagement
和pluginManagement
都是可繼承元素,但這不是全部.
所有可繼承元素:
groupId
version
description
organization
inceptionYear
創始年份url
developers
contributors
distributionManagement
部署配置issueManagement
缺陷跟蹤ciManagement
持續集成(Continuous Integration
)管理scm
版本控制信息mailingLists
郵件列表信息properties
dependencies
dependencyManagement
pluginManagement
repositories
build
reporting
子
通過parent
引入就可以享受父模塊提供的便利.
parent
中有一個relativePath
元素用於指定父模塊的pom.xml
位置,默認值是../pom.xml
,如果不符合這種結構,可以另行指定.
import 依賴範圍
我們在一個新的項目/模塊中,如果期望複用其他POM
中dependencyManagement
元素的所有配置,我們可以通過繼承或拷貝該配置實現.
因爲maven
只支持單繼承,如果當前項目已經繼承了一個父模塊,此時即可通過import
導入的方式來複用其他POM
中的dependencyManagement
配置。需要注意的是,由於import
依賴範圍的特殊性,其一般指向的是打包類型爲pom
的模塊。故其type只能爲pom.
<parent>
<groupId>com.yan</groupId>
<artifactId>xxx-parent</artifactId>
<version>xxxx</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<!-- 必須是pom -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
聚合與繼承的比較
- 不同
- 目的不同,聚合是爲了集成構建,繼承是爲了消除重複
- 聚合知道被聚合的模塊,反之不知;繼承則是子知父,父不知子
- 相同
packaging
均爲pom
,這意味着項目可以同時是聚合模塊和父模塊.- 都爲構建提供方便
反應堆
就是決定構建順序的構建結構.
單模塊的反應堆就是它本身,如果有父模塊,先構建父模塊.
如果是聚合模塊,那麼module
定義的順序決定了構建順序.
靈活構建
大多數時候,用戶都是一次性構建整個項目,但有些時候用戶可能僅僅需要構建某個模塊,即用戶需要裁剪反應堆來實現構建指定模塊的目的。在Maven
命令行中可通過相關選項參數實現反應堆的裁剪
-
-pl
,projects
:構建指定模塊,多個模塊用逗號進行分隔mvn package -pl m_a, m_b
-
-am
,-also-make
:同時構建所列模塊的父模塊mvn package -pl m_a -am
-
-amd
,-also-make-dependents
:同時子模塊mvn package m_parent -amd
-
-rf
,-resume-from
:從指定模塊開始構建mvn -rf
Maven屬性
內置屬性
主要有兩個常用內置屬性:
basedir
:項目根目錄,即包含pom.xml
的目錄version
:表示項目版本
POM屬性
project.build.sourceDirectory
:項目的主源碼目錄,默認爲src/main/java
.project.build.testSourceDirectory
:項目的測試源碼目錄,默認爲src/test/java
.project.build.directory
:項目構建輸出目錄,默認爲target
.project.outputDirectory
:項目主代碼編譯輸出目錄,默認爲target/classes
project.testOutputDirectory
:項目測試代碼編譯輸出目錄,默認爲target/testclasses
project.groupId
project.artifactId
project.version
project.build.finalName
:項目打包輸出文件的名稱,默認爲${project.artifactId}-${project.version}
自定義屬性
用戶可以在POM
的properties
元素下自定義屬性
settings屬性
可以用以settings.
開頭的屬性引用settings.xml
中的值,如settings.localRepository
指向本地倉庫的地址.
Java系統屬性
所有Java系統都可以使用Maven
屬性引用.使用mvn help:system
查看所有的Java系統屬性.
環境變量屬性
所有環境變量都可以使用以env.
開頭的Maven
屬性引用.使用mvn help:system
查看所有的環境變量屬性.
資源過濾
Maven
屬性默認只有在POM
中才會被解析,因此有時會需要讓Maven
解析資源文件(位於src/main/resources
)中的Maven
屬性.
資源文件的處理需要通過maven-resources-plugin
,它默認的行爲只是將項目主資源文件複製到主代碼編譯輸出目錄中,將測試資源文件複製到測試代碼編譯輸出目錄中.若要開啓資源過濾,需要配置<filtering>
爲真:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<resources>
<resource>
<directory>${project.build.sourceDirectory}</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</plugin>
ToolChains
默認路徑是~/.m2/toolchains.xml
.
工具鏈是一個預配置的對象,Maven
插件可將其用於工具配置檢索(位置和其他信息)。
最常用的就是Jdk
版本的選擇,還提供了自定義工具鏈的方法.
使用工具鏈,需要配置兩個基本組件:
- 項目
POM
中的maven-toolchains-plugin
, - 本機上的
toolchains.xml
文件。
實戰
Jdk
版本工具鏈示例:
-
在
~/.m2/toolchains.xml
中:<?xml version="1.0" encoding="UTF8"?> <toolchains> <!-- JDK toolchains --> <toolchain> <type>jdk</type> <provides> <version>1.5</version> <vendor>sun</vendor> </provides> <configuration> <jdkHome>/path/to/jdk/1.5</jdkHome> </configuration> </toolchain> <toolchain> <type>jdk</type> <provides> <version>1.6</version> <vendor>sun</vendor> </provides> <configuration> <jdkHome>/path/to/jdk/1.6</jdkHome> </configuration> </toolchain> <!-- other toolchains --> <toolchain> <type>netbeans</type> <provides> <version>5.5</version> </provides> <configuration> <installDir>/path/to/netbeans/5.5</installDir> </configuration> </toolchain> </toolchains>
-
pom.xml
中<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-toolchains-plugin</artifactId> <version>1.1</version> <executions> <execution> <goals> <goal>toolchain</goal> </goals> </execution> </executions> <configuration> <toolchains> <jdk> <version>1.5</version> <vendor>sun</vendor> </jdk> </toolchains> </configuration> </plugin> </plugins>
注
3.3.1版本開始可以使用
--global-toolchains file
來指定toolchains
的配置位置,但還是強烈建議放在默認目錄~/.m2
下.
可執行jar包
maven-jar-plugin
打的jar
包不可執行,需要藉助maven-shade-plugin
來配置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${你的主類全類名}</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
更多信息參考:maven-shade-plugin.
部署
在pom.xml
中加入
<distributionManagement>
<!--release倉庫-->
<repository>
<id>swb</id>
<url>http://repo.cnswb.com/repository/maven-releases/</url>
</repository>
<!--快照倉庫-->
<snapshotRepository>
<id>swb</id>
<url>http://repo.cnswb.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
執行命令mvn clean deploy
,如果當前項目版本爲快照版本則發佈至snapshotRepository
,否則是repository
.
升級
普通升級都是從官網下載最新安裝包到本機解壓後從新指定環境變量PATH
。
但還有更好的方式,即創建一個軟連接用來統一代理,這樣每次只需改變軟連接的目標地址實現升級了。
在/opt/apache
目錄下創建一個軟連接maven
,用它來指向想要升級的Maven
目錄,環境變量中的M2_HOME
設置爲/opt/apache/maven
。
比如從當前爲3.6.1
:
ln -s /opt/apache/apache-maven-3.6.1 /opt/apache/maven
升級爲3.6.3
:
rm -rf /opt/apache/maven
ln -s /opt/apache/apache-maven-3.6.3 /opt/apache/maven
升級後查看:
yan@yan-PC:/opt$ ll /opt/apache
總用量 16
drwxr-xr-x 4 yan yan 4096 3月 25 14:37 .
drwxr-xr-x 26 yan yan 4096 3月 25 10:52 ..
drwxr-xr-x 6 yan yan 4096 3月 25 14:37 apache-maven-3.6.1
drwxr-xr-x 6 yan yan 4096 3月 25 10:57 apache-maven-3.6.3
lrwxrwxrwx 1 yan yan 30 3月 25 10:56 maven -> /opt/apache/apache-maven-3.6.3
私服
目前,我們的私服倉庫結構如下: