Maven是構(gòu)建工具,能把項(xiàng)目抽象成POM(project object model)恭理,Maven使用POM對項(xiàng)目進(jìn)行構(gòu)建拯辙、打包、文檔化等操作颜价。最重要的是解決了項(xiàng)目需要類庫的依賴管理涯保,簡化了項(xiàng)目開發(fā)環(huán)境搭建的過程,使得我們開發(fā)一個從簡單到大型的復(fù)雜項(xiàng)目變得很容易周伦。
Maven介紹
Maven采用了不同方式對項(xiàng)目構(gòu)建進(jìn)行抽象夕春,比如源碼位置總是在src/main/java,配置文件則在src/main/resources中专挪,編譯好的類總是放在項(xiàng)目的target目錄下及志,總的來說,Maven實(shí)現(xiàn)了以下目標(biāo):
- 使構(gòu)建項(xiàng)目變得很容易寨腔,Maven屏蔽了構(gòu)建的復(fù)雜過程速侈。比如,你只需要輸入maven package就可以構(gòu)建整個Java項(xiàng)目迫卢。
- 統(tǒng)一了構(gòu)建項(xiàng)目的方式倚搬,不同人、不同公司的項(xiàng)目都有同樣的描述項(xiàng)目和構(gòu)建項(xiàng)目的方式乾蛤,Maven通過pom.xml來描述項(xiàng)目每界,并提供一系列插件來構(gòu)建項(xiàng)目。
- 提出了一套開發(fā)項(xiàng)目的最佳實(shí)踐幻捏,而不用每個項(xiàng)目都有不同結(jié)構(gòu)和構(gòu)建方式盆犁,比如源代碼在src/main/java中,測試代碼在src/test/java中篡九,項(xiàng)目需要的配置文件則放在src/main/resources中。
- 包含不同環(huán)境項(xiàng)目的構(gòu)建方式
- 解決了類庫依賴的問題醋奠,只需要聲明使用的類庫榛臼,Maven會自動從倉庫下載依賴的jar包伊佃,并能協(xié)助你管理jar包之間的沖突。
POM文件
Maven的核心是pom.xml沛善,用XML方式描述了項(xiàng)目模型航揉,如下:
<?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:表示項(xiàng)目所屬的組,通常是一個公司或組織的名稱金刁,如org.springframework;
artifactId: 項(xiàng)目唯一的標(biāo)志帅涂,比如,有spring-boot-starter-web尤蛮、spring-boot-devtools媳友。groupId和artifactId能唯一標(biāo)識一個項(xiàng)目或者一個庫,我們通常稱之為項(xiàng)目坐標(biāo)产捞。
packaing: 項(xiàng)目的類型醇锚,常用的有jar和war兩種,jar表示項(xiàng)目會打包成一個jar包坯临,這是Spring Boot的默認(rèn)使用方式焊唬。
version:項(xiàng)目的版本號
通常來說,項(xiàng)目版本號分三段看靠,主版本號.次版本號.修訂版本號赶促。主版本號變動代表架構(gòu)變動或者不兼容實(shí)現(xiàn),次版本號是兼容性修改挟炬、功能增強(qiáng)芳杏,修訂版本則是bug修復(fù)。
modelVersion: 代表pom文件的Maven的版本
properties 是全局屬性的配置
dependencies:此元素下包含了多個dependency辟宗,用來聲明項(xiàng)目的依賴爵赵,這是pom最核心的部分。
dependency:包含在dependencies中泊脐,用來聲明項(xiàng)目的依賴空幻。
scope: scope代表此類庫與項(xiàng)目的關(guān)系,默認(rèn)是compile容客,也就是編譯和打包都需要此類庫秕铛。test表示僅僅在單元測試的時候需要;provided表示在編譯階段需要此類庫缩挑,但打包階段不需要但两,這是因?yàn)轫?xiàng)目的目標(biāo)環(huán)境已經(jīng)提供了。runtime表示在編譯和打包的時候都不需要供置,但在運(yùn)行的時候需要谨湘。
build:此項(xiàng)在pom中可選,build包含了多個插件plugin,用來輔助項(xiàng)目構(gòu)建紧阔。
plugins:對插件的管理
pom的繼承
可以通過parent實(shí)現(xiàn)POM的繼承以完成統(tǒng)一配置管理坊罢,子POM中的配置優(yōu)先級高于父POM。
例如擅耽,以Spring Boot為基礎(chǔ)的項(xiàng)目中活孩,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版本了,起到了統(tǒng)一控制版本的作用:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
能夠繼承的元素如下:
- groupId,version
- Project Config
- Dependencies
- Plugin configuration
此外乖仇,<dependencyManagement>和<pluginManagement>可以統(tǒng)一做依賴和插件的配置管理憾儒,不同于<dependencies>和<plugins>的是,如果子POM中沒有聲明<dependency>和<plugin>則并不生效乃沙。
標(biāo)準(zhǔn)Web項(xiàng)目結(jié)構(gòu)
在Maven中起趾,一個Web項(xiàng)目的標(biāo)準(zhǔn)結(jié)構(gòu),如下所示:
其中:
- src/main/java Java代碼目錄
- src/main/resources 配置文件目錄
- src/main/webapp webapp根目錄
- src/test/java 測試代碼目錄
- src/test/resources 測試配置目錄
- target/classes 代碼編譯結(jié)果目標(biāo)目錄
- target/test-classes 測試代碼編譯結(jié)果目標(biāo)目錄
自定義項(xiàng)目結(jié)構(gòu)
<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中冷蚂,同時編譯結(jié)果目錄變成了./build缭保。此外,在maven-war-plugin中蝙茶,也把Web目錄的war源碼目錄改為了./WebContent艺骂。
配置倉庫
在最開始的maven配置文件中,有個repository的配置隆夯。此外钳恕,Maven還有一個鏡像庫的配置,即在Maven的setting.xml中配置Maven鏡像庫蹄衷。和pom.xml中的repository不同的是忧额,鏡像會攔截住對遠(yuǎn)程中央庫的請求,只在鏡像庫中進(jìn)行依賴的搜索以及下載愧口。而如果只是配置了repository睦番,那么當(dāng)在repository中找不到想應(yīng)的依賴時,會繼續(xù)去遠(yuǎn)程中央庫進(jìn)行搜索和下載耍属。
添加倉庫鏡像
進(jìn)入Maven的安裝目錄, 進(jìn)入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在構(gòu)建項(xiàng)目中報(bào)出缺少依賴庫,請暫時注釋掉這個鏡像并重新構(gòu)建领舰,切換到中心倉庫夫嗓。
項(xiàng)目構(gòu)建流程
Maven的構(gòu)建生命周期中幾個常見階段如下:
- validate:驗(yàn)證項(xiàng)目以及相關(guān)信息是否正確迟螺。
- compile:編譯源代碼和相關(guān)資源文件。
- test:對測試代碼進(jìn)行測試啤月。
- package:根據(jù)不同的項(xiàng)目類型進(jìn)行打包煮仇。
- verify:驗(yàn)證打包的正確性劳跃。
- install:將打好的包谎仲,安裝到本地。
- deploy:將打好的包發(fā)布到遠(yuǎn)程庫中刨仑。
profile
現(xiàn)實(shí)開發(fā)中一個常見的需求就是需要根據(jù)不同的環(huán)境打包不同的文件郑诺。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種環(huán)境,對應(yīng)每一種環(huán)境轻抱,其資源文件路徑都不一樣飞涂。在使用MVN時,使用-p參數(shù)指定profile即可生效祈搜。
Maven常用插件
- maven-source-plugin:源碼發(fā)布插件较店,綁定在compile階段,執(zhí)行jar goal容燕,將源碼以jar包的形式發(fā)布出去梁呈。
- maven-javadoc-plugin:javadoc插件,將源碼的javadoc發(fā)布出去蘸秘。
- maven-tomcat7-plugin:此插件可以直接使用Tomcat運(yùn)行Web項(xiàng)目官卡,常用的命令是mvn tomcat7:run。同樣的還有jetty-maven-plugin
- maven-shade-plugin:此插件是Maven常用的打包插件醋虏,一般將其綁定在package階段寻咒,執(zhí)行其shade goal。其能夠?qū)⒃创a和依賴的第三方資源打包在一起以供獨(dú)立運(yùn)行颈嚼。
- maven-assesmbly-plugin:和maven-shade-plugin一樣也是打包插件毛秘,但是其功能更加強(qiáng)大,輸出壓縮包格式除了jar外粘舟,還支持tar熔脂、zip、gz等柑肴。
- maven-gpg-plugin:此插件是jar包的簽名插件霞揉,可以對自己發(fā)布的jar包進(jìn)行簽名。
Maven的常用命令
mvn compile:編譯Maven工程晰骑,進(jìn)入項(xiàng)目目錄适秩,運(yùn)行mvn compile
mvn package:編譯并打包工程绊序,根據(jù)pom.xml中元素packaging是jar還是war進(jìn)行打包。
mvn install:打包并安裝到本地倉庫秽荞。如果你的項(xiàng)目是一個基礎(chǔ)類庫骤公,本地其他項(xiàng)目也需要,則需要安裝到本地倉庫扬跋。這樣阶捆,其他本地Maven項(xiàng)目就可以通過項(xiàng)目坐標(biāo)引用。
mvn deploy:同install钦听,但打包并安裝到遠(yuǎn)程倉庫洒试。
mvn clean:刪除target目錄。
將依賴復(fù)制到指定目錄:mvn dependency:copy-dependencies -DoutputDirectory=./lib
部署非Maven項(xiàng)目的jar包:mvn deploy:deploy-file -DgroupId=[groupId] -DartifactId=[artifactId] -Dversion=[version] -Dpackaging=jar -Dfile=[jarFilePath] -Durl=[repositoryUrl]
執(zhí)行指定類中的main方法:mvn exec:java -Dexec.mainClass=[mainClass]
查看依賴樹:mvn dependency:tree
執(zhí)行指定的測試用例:mvn test -Dtest=[ClassName]#[MethodName] 其中#[MethodName]為要運(yùn)行的方法朴上,支持*通配符
跳過測試階段且不編譯測試用例類: mvn -Dmaven.test.skip=true ...
跳過測試階段但編譯測試用例類:mvn -DskipTests ...
使用指定的POM文件或者指定目錄下的pom.xml運(yùn)行:mvn -f [file/dir] ...
此外垒棋,可以使用-q參數(shù)是Maven的日志輸出只包含錯誤信息。
Maven倉庫
Maven的倉庫有兩大類痪宰,第一類是遠(yuǎn)程倉庫叼架,包括中心倉庫,位于http://search.maven.org/; 還包括鏡像倉庫衣撬,比如國內(nèi)常用的鏡像http://maven.aliyun.com/nexus/乖订,還有利用nexus軟件自己搭建的公司私服。
還有一類是本地倉庫淮韭,位于用戶目錄的.m2目錄下垢粮,遠(yuǎn)程倉庫加載的庫總是會先放到本地倉庫作為緩存。
最后
下面是一些提示:
在項(xiàng)目版本號中加入SNAPSHOT后綴作為快照版本靠粪,可以使得Maven每次都能自動獲取最新版本而無需頻繁更新版本號蜡吧。
mvn -DEAME=test 可以傳遞給POM參數(shù),使用${NAME}引用即可占键。
在dependency中設(shè)置optional為true昔善,可以使得此依賴不傳遞出去。
由于Maven自定義plugin很復(fù)雜畔乙,不夠靈活君仆,因此很多時候都是結(jié)合Ant的靈活性和Maven一起使用的。
-
日常開發(fā)中一個工程可能比較龐大牲距,這時可以把這個工程拆分成多個子模塊來管理返咱。一個多模塊工程包含一個父POM,在其中定義了它的子模塊牍鞠,每個子模塊都是一個獨(dú)立的工程咖摹。
<project> ... <packaging>pom</packaging> <modules> <module>module-1</module> <module>module-2</module> </modules> </project>
參考書籍:
- 《Java工程師修煉之道》
- 《Spring Boot2精髓》