Maven是構建工具,能把項目抽象成POM(project object model),Maven使用POM對項目進行構建、打包、文檔化等操作。最重要的是解決了項目需要類庫的依賴管理,簡化了項目開發環境搭建的過程,使得我們開發一個從簡單到大型的複雜項目變得很容易。
Maven介紹
Maven採用了不同方式對項目構建進行抽象,比如源碼位置總是在src/main/java,配置文件則在src/main/resources中,編譯好的類總是放在項目的target目錄下,總的來說,Maven實現了以下目標:
- 使構建項目變得很容易,Maven屏蔽了構建的複雜過程。比如,你只需要輸入maven package就可以構建整個Java項目。
- 統一了構建項目的方式,不同人、不同公司的項目都有同樣的描述項目和構建項目的方式,Maven通過pom.xml來描述項目,並提供一系列插件來構建項目。
- 提出了一套開發項目的最佳實踐,而不用每個項目都有不同結構和構建方式,比如源代碼在src/main/java中,測試代碼在src/test/java中,項目需要的配置文件則放在src/main/resources中。
- 包含不同環境項目的構建方式
- 解決了類庫依賴的問題,只需要聲明使用的類庫,Maven會自動從倉庫下載依賴的jar包,並能協助你管理jar包之間的衝突。
POM文件
Maven的核心是pom.xml,用XML方式描述了項目模型,如下:
<?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>me.rowkey</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>antares</name>
<url>http://maven.apache.org</url>
<repositories>
<repository>
<id>nexus-suishen</id>
<name>Nexus suishen</name>
<url>http://maven.etouch.cn/nexus/content/groups/public/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</repository>
</repositories>
<properties>
<slf4j.version>1.7.21</slf4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf5j.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
pom.xml通常有以下元素:
-
groupId:表示項目所屬的組,通常是一個公司或組織的名稱,如org.springframework;
-
artifactId: 項目唯一的標誌,比如,有spring-boot-starter-web、spring-boot-devtools。groupId和artifactId能唯一標識一個項目或者一個庫,我們通常稱之爲項目座標。
-
packaing: 項目的類型,常用的有jar和war兩種,jar表示項目會打包成一個jar包,這是Spring Boot的默認使用方式。
-
version:項目的版本號
通常來說,項目版本號分三段,主版本號.次版本號.修訂版本號。主版本號變動代表架構變動或者不兼容實現,次版本號是兼容性修改、功能增強,修訂版本則是bug修復。
-
modelVersion: 代表pom文件的Maven的版本
-
properties 是全局屬性的配置
-
dependencies:此元素下包含了多個dependency,用來聲明項目的依賴,這是pom最核心的部分。
-
dependency:包含在dependencies中,用來聲明項目的依賴。
-
scope: scope代表此類庫與項目的關係,默認是compile,也就是編譯和打包都需要此類庫。test表示僅僅在單元測試的時候需要;provided表示在編譯階段需要此類庫,但打包階段不需要,這是因爲項目的目標環境已經提供了。runtime表示在編譯和打包的時候都不需要,但在運行的時候需要。
-
build:此項在pom中可選,build包含了多個插件plugin,用來輔助項目構建。
-
plugins:對插件的管理
pom的繼承
可以通過parent實現POM的繼承以完成統一配置管理,子POM中的配置優先級高於父POM。
例如,以Spring Boot爲基礎的項目中,pom.xml文件中往往有如下屬性:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
這樣spring-boot-starter-*依賴就不需要指明version版本了,起到了統一控制版本的作用:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
能夠繼承的元素如下:
- groupId,version
- Project Config
- Dependencies
- Plugin configuration
此外,<dependencyManagement>和<pluginManagement>可以統一做依賴和插件的配置管理,不同於<dependencies>和<plugins>的是,如果子POM中沒有聲明<dependency>和<plugin>則並不生效。
標準Web項目結構
在Maven中,一個Web項目的標準結構,如下所示:
2291536764978_.pic.jpg
其中:
- src/main/java Java代碼目錄
- src/main/resources 配置文件目錄
- src/main/webapp webapp根目錄
- src/test/java 測試代碼目錄
- src/test/resources 測試配置目錄
- target/classes 代碼編譯結果目標目錄
- target/test-classes 測試代碼編譯結果目標目錄
自定義項目結構
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test/java</testSourceDirectory>
<testResources>
<testResource>
<directory>test/resources</directory>
</testResource>
</testResources>
<directory>build</directory>
</build>
這裏,Java代碼目錄移到了./src中,測試代碼目錄移到了./test/java中,測試資源也移到了./test/resources中,同時編譯結果目錄變成了./build。此外,在maven-war-plugin中,也把Web目錄的war源碼目錄改爲了./WebContent。
配置倉庫
在最開始的maven配置文件中,有個repository的配置。此外,Maven還有一個鏡像庫的配置,即在Maven的setting.xml中配置Maven鏡像庫。和pom.xml中的repository不同的是,鏡像會攔截住對遠程中央庫的請求,只在鏡像庫中進行依賴的搜索以及下載。而如果只是配置了repository,那麼當在repository中找不到想應的依賴時,會繼續去遠程中央庫進行搜索和下載。
添加倉庫鏡像
-
進入Maven的安裝目錄, 進入conf目錄,編輯settings.xml。
-
找到mirrors元素,添加如下倉庫鏡像
<mirror> <id>nexus-aliyun</id> <mirrorOf>central</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
注意:鏡像不一定包含所有的依賴庫,如果Maven在構建項目中報出缺少依賴庫,請暫時註釋掉這個鏡像並重新構建,切換到中心倉庫。
項目構建流程
Maven的構建生命週期中幾個常見階段如下:
- validate:驗證項目以及相關信息是否正確。
- compile:編譯源代碼和相關資源文件。
- test:對測試代碼進行測試。
- package:根據不同的項目類型進行打包。
- verify:驗證打包的正確性。
- install:將打好的包,安裝到本地。
- deploy:將打好的包發佈到遠程庫中。
profile
現實開發中一個常見的需求就是需要根據不同的環境打包不同的文件。Maven中的profile即可解決此問題。
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<resources.dir>src/main/resources/dev</resources.dir>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<resources.dir>src/main/resources/test</resources.dir>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<resources.dir>src/main/resources/prod</resources.dir>
</properties>
</profile>
</profiles>
<build>
<resources>
<resource>
<directory>${resources.dir}}</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
如此,分爲dev、test和prod共3種環境,對應每一種環境,其資源文件路徑都不一樣。在使用MVN時,使用-p參數指定profile即可生效。
Maven常用插件
- maven-source-plugin:源碼發佈插件,綁定在compile階段,執行jar goal,將源碼以jar包的形式發佈出去。
- maven-javadoc-plugin:javadoc插件,將源碼的javadoc發佈出去。
- maven-tomcat7-plugin:此插件可以直接使用Tomcat運行Web項目,常用的命令是mvn tomcat7:run。同樣的還有jetty-maven-plugin
- maven-shade-plugin:此插件是Maven常用的打包插件,一般將其綁定在package階段,執行其shade goal。其能夠將源碼和依賴的第三方資源打包在一起以供獨立運行。
- maven-assesmbly-plugin:和maven-shade-plugin一樣也是打包插件,但是其功能更加強大,輸出壓縮包格式除了jar外,還支持tar、zip、gz等。
- maven-gpg-plugin:此插件是jar包的簽名插件,可以對自己發佈的jar包進行簽名。
Maven的常用命令
-
mvn compile:編譯Maven工程,進入項目目錄,運行mvn compile
-
mvn package:編譯並打包工程,根據pom.xml中元素packaging是jar還是war進行打包。
-
mvn install:打包並安裝到本地倉庫。如果你的項目是一個基礎類庫,本地其他項目也需要,則需要安裝到本地倉庫。這樣,其他本地Maven項目就可以通過項目座標引用。
-
mvn deploy:同install,但打包並安裝到遠程倉庫。
-
mvn clean:刪除target目錄。
-
將依賴複製到指定目錄:mvn dependency:copy-dependencies -DoutputDirectory=./lib
-
部署非Maven項目的jar包:mvn deploy:deploy-file -DgroupId=[groupId] -DartifactId=[artifactId] -Dversion=[version] -Dpackaging=jar -Dfile=[jarFilePath] -Durl=[repositoryUrl]
-
執行指定類中的main方法:mvn exec:java -Dexec.mainClass=[mainClass]
-
查看依賴樹:mvn dependency:tree
-
執行指定的測試用例:mvn test -Dtest=[ClassName]#[MethodName] 其中#[MethodName]爲要運行的方法,支持*通配符
-
跳過測試階段且不編譯測試用例類: mvn -Dmaven.test.skip=true ...
-
跳過測試階段但編譯測試用例類:mvn -DskipTests ...
-
使用指定的POM文件或者指定目錄下的pom.xml運行:mvn -f [file/dir] ...
此外,可以使用-q參數是Maven的日誌輸出只包含錯誤信息。
Maven倉庫
Maven的倉庫有兩大類,第一類是遠程倉庫,包括中心倉庫,位於http://search.maven.org/; 還包括鏡像倉庫,比如國內常用的鏡像http://maven.aliyun.com/nexus/,還有利用nexus軟件自己搭建的公司私服。
還有一類是本地倉庫,位於用戶目錄的.m2目錄下,遠程倉庫加載的庫總是會先放到本地倉庫作爲緩存。
最後
下面是一些提示:
-
在項目版本號中加入SNAPSHOT後綴作爲快照版本,可以使得Maven每次都能自動獲取最新版本而無需頻繁更新版本號。
-
mvn -DEAME=test 可以傳遞給POM參數,使用${NAME}引用即可。
-
在dependency中設置optional爲true,可以使得此依賴不傳遞出去。
-
由於Maven自定義plugin很複雜,不夠靈活,因此很多時候都是結合Ant的靈活性和Maven一起使用的。
-
日常開發中一個工程可能比較龐大,這時可以把這個工程拆分成多個子模塊來管理。一個多模塊工程包含一個父POM,在其中定義了它的子模塊,每個子模塊都是一個獨立的工程。
<project> ... <packaging>pom</packaging> <modules> <module>module-1</module> <module>module-2</module> </modules> </project>