一年前,當我和小伙伴小龍一起做一個外包項目的時候,受到了嚴重的鄙視。我那時候還不知道 Maven,所以搭建項目用的還是最原始的方式,小龍不得已在導入項目的時候花了很長時間去下載項目依賴的開源類庫。 出於對我的尊重,小龍沒有破口大罵,而是非常委婉地說了一句:“二哥,你好歹也有一定的知名度了,竟然沒用 ...
一年前,當我和小伙伴小龍一起做一個外包項目的時候,受到了嚴重的鄙視。我那時候還不知道 Maven,所以搭建項目用的還是最原始的方式,小龍不得已在導入項目的時候花了很長時間去下載項目依賴的開源類庫。
出於對我的尊重,小龍沒有破口大罵,而是非常委婉地說了一句:“二哥,你好歹也有一定的知名度了,竟然沒用 Maven 構建項目,真讓我大開眼界啊。”
作為一名富有上進心的程式員,不能忍啊。藉此機會,有必要隆重地向大家介紹一下 Maven 了。
01、Maven 是什麼?
不管英文功底好不好,先看看官網給出的介紹語吧:
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
大致的意思就是說,Apache Maven 是一個項目管理和自動化構建工具,基於項目對象模型(POM)的概念,可以管理項目的構建、報告以及文檔。作為 Apache 組織中的一個頗為成功的開源項目,Maven 主要服務於基於 Java 的項目構建、依賴管理和項目信息管理。
Maven 採用了約定優先配置的原則,這些原則如下表所示:
目錄 | 目的 |
---|---|
${basedir} |
存放 pom.xml 和所有的子目錄 |
${basedir}/src/main/java |
存放 Java 源代碼 |
${basedir}/src/main/resources |
存放項目的資源文件,比如說 log4j.properties |
${basedir}/src/test/java |
存放測試類 |
${basedir}/src/test/resources |
存放測試用的資源 |
${basedir}/src/main/webapp |
存放 Web 前端文件 |
${basedir}/target |
項目打包後的輸出目錄 |
${basedir}/target/classes |
項目編譯後輸出目錄 |
~/.m2/repository |
預設的 Maven 倉庫目錄(~表示用戶目錄) |
使用約定優先配置帶來的最大好處就是項目的目錄結構圖非常的統一,不同的開發者在開發一個 Maven 項目的時候,文件存放位置幾乎沒有差別,省去了很多不必要的麻煩,有利於促進項目團隊的標準化。
我們這個年代非常崇尚開源精神,幾乎所有的 Java 項目都會借用一些第三方的開源類庫,這些類庫可以通過依賴的方式引入到項目中來。但隨著依賴的增多,版本衝突、依賴臃腫的問題就會接踵而來。手工解決這些問題是十分枯燥的,幸運的是 Maven 提供了一個優秀的解決方案,它通過一個三維的坐標(<groupId>
、<artifactId>
、<version>
)來準確地定位每一個開源類庫。
另外,我認為 Maven 特別優秀的一點是,它把項目依賴的所有開源類庫都從遠程中央倉庫下載到了指定的本地倉庫中,也就是說,這些開源類庫可以在多個項目之間共用,無需重覆下載——假如我用 Maven 構建項目的話,小龍就不用下載那麼多開源類庫了,他的本地倉庫中可能已經有了——我也就不會被鄙視了。
02、配置 Maven 環境
1)安裝 Maven 之前,先確保電腦上已經安裝了 JDK。
2)去 Maven 官網下載想要的版本並解壓,下載地址為:
https://maven.apache.org/download.cgi
3)設置環境變數,主要是 MAVEN_HOME 和 Path。
4)打開命令行,輸入 mvn -v
驗證 Maven 是否配置成功。
5)Maven 的 conf 目錄下包含了一個非常重要的文件 settings.xml,一般情況下,我傾向於將該文件複製到 ~/.m2/
目錄下——建議你也這麼做。
打開該文件,在 <mirrors></mirrors>
節點下添加阿裡雲的鏡像地址(參照下麵的代碼)。為什麼要這麼做呢?因為 Maven 預設的倉庫在不翻強的情況下很難訪問到。
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
這裡需要註意的是,<mirrorOf>
的值有下麵四種方式:
*
:匹配所有遠程倉庫,也就是說任何對於中央倉庫的請求都會轉至該鏡像。external:*
:匹配所有不在本機上的遠程倉庫。repo1,repo2
:匹配倉庫 repo1 和 repo2,使用逗號分隔多個遠程倉庫。*,!repo
:匹配所有遠程倉庫,repo 除外,使用感嘆號將倉庫從匹配中排除。
6)在 Eclipse 下依次選擇菜單 Window → Show View → Other → Maven → Maven Workspace Build,查看鏡像是否配置成功(我習慣了使用 Eclipse,所以請見諒,不過不管使用哪種集成開發環境,思路和步驟都大差不差)。
03、快速創建 Maven 項目
為了儘快步入重點,這一小節我會有意的避重就輕,沒必要的步驟會略過。
1)在 Eclipse 中新建項目的時候選擇 Maven Project。
2)在接下來選擇項目類型的時候,選擇 maven-archetype-quickstart,如下圖所示。
3)然後指定項目參數的時候填寫 group id 和 artifact id。
4)項目創建成功後的目錄結構圖如下圖所示。
Maven 3 預設使用的依然是 JDK 1.5,不過我們可以為其配置更高版本的 JDK,後面會聊到。
04、詳細分析 pom.xml
毫無疑問,Maven 項目的靈魂只有一個,那就是 pom.xml 文件,所以接下來我會詳細地對其進行分析。
1)項目基本信息
pom.xml 文件的第一部分主要用來描述項目的基本信息。
<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>com.cmower</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>test</name>
</project>
①、<project>
是 pom.xml 的根元素,聲明瞭相關的命名空間。
②、<modelVersion>
指定了當前項目對象模型(POM)的版本,對於 Maven 3.x 來說,該值只能是 4.0.0。
③、<groupId>
定義了項目的組名,這個組往往和項目所在的組織或公司關聯。
④、<artifactId>
定義了當前 Maven 項目在組中唯一的 ID。
⑤、<version>
定義了項目的版本號,SNAPSHOT
為快照的意思,也就是說該項目還處於開發階段。
⑥、<packaging>
定義了項目的打包類型,可選值有 war、jar 等。
⑦、<name>
定義了項目的名稱。
2)變數配置信息
pom.xml 文件的第二部分通常用來配置一些變數信息。
<properties>
<spring.version>5.1.5.RELEASE</spring.version>
</properties>
有了變數的配置信息後,可以通過 ${spring.version}
的形式來調用這些配置項。這樣做的好處顯而易見,當依賴項的版本升級的時候,可以直接修改變數值即可。
3)依賴管理
阿裡雲的 Maven 倉庫下有各種各樣的第三方類庫,換句話說就是,只有你想不到的,沒有你找不到的。大多數 Maven 項目的依賴項列表都會很長很長,為了便於說明,下麵我只列出某些具有特色的。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
①、上文中曾提到,<groupId>
、<artifactId>
、<version>
合起來可以準確地定位一個依賴項。那怎麼找到想要的依賴項呢?
第一步,進入 MavenRepository 網站,地址如下:
http://mvnrepository.com
然後在搜索框中輸入第三方類庫的關鍵字,比如說「spring-core」,點擊「search」按鈕,可以查看到該類庫的鏈接導航。
第二步,點擊鏈接進入到「spring-core」的主頁,可以看到所有版本的「spring-core」,選擇一個使用率最高的。使用率高在一定程度上表明這個版本的類庫最穩定,它已經得到了廣大程式員的認可。
第三步,進入該版本的主頁,只需要左鍵輕輕地在 「Maven」選項卡內點一下,就已經把該類庫的 Maven 依賴信息複製到粘貼板了(不需要「Ctrl+C」,非常的人性化),如下圖所示。
第四步,將類庫的依賴信息粘貼到 pom.xml 文件的 <dependencies>
節點下,然後按下快捷鍵「Ctrl+S」保存。緊接著,依次展開 test → Java Resources → Libraries → Maven Dependencies 節點,你可以看到該類庫已經悄悄地添加進來了。
②、 <exclusions>
主要用於排除依賴。
有時候,我們引入的依賴中可能會包含一些不想要的依賴包,我們想引入自己想要的,這時候就要用到排除依賴了。
使用 <exclusion>
的時候只需要指定 groupId 和 artifactId 就行了,並不需要 version,這是因為 groupId 和 artifactId 就可以定位某種類型的依賴。
③、 <scope>
用來控制依賴的範圍。
test:測試依賴範圍。典型的例子是 Jnuit,它只有在編譯測試代碼及運行測試的時候才需要。
compile:編譯依賴範圍(其實不止是編譯,對測試、運行同樣有效),預設項,如果沒有指定,就會預設使用該依賴範圍。
provided:提供依賴範圍。對編譯和測試有效,但在運行時候無效。
runtime:運行時依賴範圍。對測試和運行有效,但在編譯時無效。
PS:如果不知道選哪一種,預設就對了。
4)構建配置
<build>
元素中包含了執行 Maven 構建周期目標所需的插件以及相關的配置。
<build>
<finalName>test</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
①、<finalName>
,打成 jar 包或者 war 包時的名稱。上文中曾提到,項目打包後的輸出目錄為 ${basedir}/target
。
②、<plugins>
用於指定項目在構建過程中使用的插件。
、
、
用於確定使用的插件。
,該插件所需要的特殊配置。Maven 3 預設使用的是 JDK 1.5,本例中我們使用了 JDK 1.8。
③、<resources>
描述了各個資源在 Maven 項目中的具體路徑。
,資源文件的路徑,預設位於
${basedir}/src/main/resources/
目錄下。,用於指定在構建過程中被處理的資源文件;對應
用於省去不被處理的資源文件。
05、使用 Maven 對項目進行清理、編譯、測試、打包
1)清理:mvn clean
,該命令會刪除 target 目錄。可以直接在命令行中執行該命令,只需要切換到項目所在的路徑下即可。
2)編譯:mvn complie
,該命令會編譯 src/main/java 目錄下的源碼。同時,Maven 還會處理在 src/main/resources 目錄下的資源文件,確保它們作為編譯的一部分。
不過,很遺憾的是,執行該命令會報錯。該命令給出的提示是,查看 [Help 1] 給出的地址,我嘗試了一下,可以將 mvn complie
命令替換為 mvn compiler:compile
命令執行,結果如下圖所示。
編譯後可以在 target 目錄下查看位元組碼文件。
3)測試:mvn test
,test 命令在運行時,會執行 compile 命令;而之前我們已經執行過一次 compile 命令,為了確保結果的準確性,可以執行 mvn clean test
命令確保測試之前沒有殘餘物,結果如下圖所示。
Maven 會通過 Surefire 插件,使用 pom.xml 文件中的測試提供者(通常是 Junit)運行測試。執行 test
命令不僅會運行測試,還會產生報告文件,此時 target 目錄下的截圖如下:
4)打包:mvn install
,該命令會按照 pom.xml 文件中 <packaging>
指定的方式(本例為 jar)對編譯結果打包。同時,還會把打包好的文件放到本地的 Maven 倉庫中,以便其他項目把它當做依賴項使用。命令執行結果如下圖所示。
查看本地的 Maven 倉庫,可以看到剛剛打包好的文件。
06、最後
在 Maven 出現之前,流行的構建工具是 Ant;在 Maven 出現之後,還有一種新興的構建工具 Gradle,它有意選擇了和 Maven 相反的原則,不會強制使用者遵循刻板的構建周期。
總之,Maven 是一款優秀的構建工具,Java 項目的開發者很有必要熟練地掌握它。