導語
最近在學習Java了,以后分享的文章主要就以Java為主了,偶爾也會分享一下Objective-C方面的文章,這篇讀書筆記主要介紹了Maven的一些核心概念和常用的一些插件。
Maven
什么是Maven?
什么是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)的概念,它可以管理項目的構建眼滤、報告和文檔巴席。我們也會經常聽到有人對Maven是這樣理解的:
- Maven是一個站點和文檔工具。
- Maven擴展Ant诅需,讓你下載依賴關系漾唉。
- Maven是一組可重用的Ant腳本。
這幾個方面都是Maven的一些功能堰塌,Maven所提供的功能遠比這強大的許多毡证,不過對于我們在日常項目當中用到最多的就是管理第三方庫的依賴、項目的構建蔫仙。如果開發(fā)工具使用的是IntelliJ IDEA料睛,自動就幫你安裝好了Maven,不是的話摇邦,也可以參考下官方給出的Maven安裝教程恤煞,也是比較簡單的。接下來看下怎樣用Maven來滿足我們項目的日常需要施籍。
約定優(yōu)于配置
Maven使用約定優(yōu)于配置的原則居扒,如下所示:
目錄 | 目的 |
---|---|
${basedir} | 存放pom.xml和所有的子目錄 |
${basedir}/src/main/java | 項目的java源代碼 |
${basedir}/src/main/resources | 項目的資源,比如說property文件丑慎,springmvc.xml |
${basedir}/src/test/java | 項目的測試類喜喂,比如說Junit代碼 |
${basedir}/src/test/resources | 測試用用的資源 |
${basedir}/src/main/webapp/WEB-INF | web應用文件目錄瓤摧,web項目的信息,比如存放web.xml玉吁、本地圖片照弥、jsp視圖頁面 |
${basedir}/target | 打包輸出目錄 |
${basedir}/target/classes | 編譯輸出目錄 |
${basedir}/target/test-classes | 測試編譯輸出目錄 |
Test.java | Maven只會自動運行符合該命名規(guī)則的測試類 |
~/.m2/repository | Maven默認的本地倉庫目錄位置 |
一個maven項目在默認情況下會產生jar文件,另外进副,編譯后的classes會放在${basedir}/target/classes下面这揣,jar文件會放在${basedir}/target下面。使用約定優(yōu)于配置帶來最大的好處就是項目的統(tǒng)一影斑,任何人在使用Maven項目的時候给赞,文件的存放位置都是一樣的,通用性比較好矫户。這也是為什么我們在用intellij創(chuàng)建一個maven項目的時候片迅,需要配置源文件、資源文件路徑的原因皆辽。如下圖就是常用的幾個配置:
Maven的幾個核心概念
POM(Project Object Model)
一個項目所有的配置都放在POM文件中:定義項目的類型柑蛇、名字、管理依賴關系膳汪,定制插件的行為等等【判悖看下我自己寫的小demo中pom中配置如下:
<groupId>com.dodonew</groupId>
<artifactId>springmvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>springmvc</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- spring日志依賴 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
</dependencies>
在POM中遗嗽,groupId、artifactId鼓蜒、packaging痹换、version叫做maven坐標,它能唯一的確定一個項目都弹。有了maven坐標娇豫,我們就可以用它來指定我們的項目所依賴的其他項目、插件畅厢、或者父項目冯痢。我寫的demo很簡單,但是比較大的項目一般會分成幾個子項目框杜,在這種情況下浦楣,每個子項目就會有自己的POM文件,它們會有一個共同的父項目咪辱。這樣只要構建父項目就能夠構建所有的子項目了振劳。同時子項目的POM會繼承父項目的POM。關于多個子項目具體怎么操作油狂,在文章后面會有回答的历恐。
Maven插件
Maven常用的插件比如compiler插件寸癌、surefire插件、jar插件弱贼。比如說jar插件包含建立jar文件的目標蒸苇,compiler插件包含編譯源代碼和單元測試代碼的目標,surefire插件則是運行單元測試的目標哮洽。為什么需要這些插件呢填渠?因為maven本身不會做太多的事情,它不知道怎么樣編譯或者怎么樣打包鸟辅。它把構建的任務交給插件去做氛什。插件定義了常用的構建邏輯,能夠被重復利用匪凉。這樣做的好處是枪眉,一旦插件有了更新,那么所有maven用戶都能得到更新再层。
Maven生命周期
生命周期指項目的構建過程贸铜,它包含了一系列的有序的階段,而一個階段就是構建過程中的一個步驟聂受,比如package階段蒿秦、compiler階段等。那么生命周期階段和上面說的插件目標之間是什么關系呢蛋济?插件目標可以綁定到生命周期階段上棍鳖,一個生命周期可以綁定多個插件目標。當maven在構建過程中逐步的通過每個階段時碗旅,會執(zhí)行該階段所有的插件目標渡处。目前生命周期階段有clean、vavidate祟辟、compiler医瘫、test、package旧困、verify醇份、install、site吼具、deploy階段被芳。
Maven依賴管理
我們能夠通過maven坐標確定一個項目,換句話說馍悟,我們可以用它來解決依賴關系畔濒。在POM中,依賴關系是在dependencies部分中定義的锣咒。比如對slf4j庫和logback庫的依賴關系如下:
<dependencies>
<!-- spring日志依賴 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
</dependencies>
這個依賴關系是比較簡單的侵状,但是實際開發(fā)中我們會有復雜多的依賴關系赞弥,因為被依賴的jar文件會有自己的依賴關系,那么我們是不是也得把間接依賴的jar文件也都定義在POM中呢趣兄?答案是不需要绽左,因為maven提供了傳遞依賴的特性,會把依賴的jar文件它所依賴的庫也自動添加進來艇潭。比如spring-webmvc庫拼窥,這個庫自己又依賴spring-core、spring-beans蹋凝、spring-web鲁纠、spring-expression、spring-context鳍寂,因為依賴傳遞性改含,我們在使用spring-webmvc的時候,只需要聲明對spring-webmvc的依賴關系即可迄汛,其他的庫會自動幫你引入的捍壤。之所以能實現依賴傳遞性關鍵就在于下載spring-webmvc庫,同時也下載了pom文件鞍爱,在pom文件定義了這個庫需要的依賴關系鹃觉。
scope決定了依賴關系的適用范圍,比如junit的scope是test睹逃,那么它只會在執(zhí)行compiler:testCompile和surefire:test目標的時候才會被加載到classpath中盗扇,在執(zhí)行compiler:compile目標時是拿不到junit的。換句話說就是在maven哪個生命周期中起作用了唯卖。scope的默認值是compile粱玲,即任何時候都會被包含在classpath中躬柬,在打包的時候也會被包括進去拜轨。
Maven庫
我們所依賴的庫是從maven默認的遠程庫 (http://repo.maven.org/maven2) 下載的,這個是公有的庫允青。有時公司自己封裝了一些私有庫橄碾,這個時候我們就可以搭建自己的私有庫了。本地庫是指maven下載了插件或者jar文件后存放在本地機器上的拷貝颠锉。在Mac上法牲,它的位置在~/.m2/repository。當maven查找需要的jar文件時琼掠,它會先在本地庫中查找拒垃,只有在找不到的情況下,才會去遠程庫中找的瓷蛙。由于maven默認的遠程庫服務器在國外悼瓮,國內訪問的時候比較慢戈毒,建議替換成阿里云的鏡像,倉庫地址如下:
http://maven.aliyun.com/nexus/content/groups/public/
Maven多模塊項目POM注意的事項
denpendencyManagement
在項目開發(fā)過程中横堡,有時一個項目下面包含了幾個子模塊埋市,在多模塊的情況,POM的配置應該要注意寫什么呢命贴?我們通過一個例子來說明下道宅。
有這樣一個工程,里面有A模塊胸蛛、B模塊和C模塊污茵,A模塊需要引入junit和log4j庫,配置如下:
<dependency>
<groupId>junit</groupId>
<artifactid>junit</artifactId>
<version>3.8.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactid>log4j</artifactId>
<version>1.2.9</version>
</dependency>
此時B模塊也需要引入這兩個庫胚泌,配置如下:
<dependency>
<groupId>junit</groupId>
<artifactid>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactid>log4j</artifactId>
<version>1.2.16</version>
</dependency>
會發(fā)現A模塊和B模塊對junit和log4j庫依賴的版本是不同的省咨,出現這種情況是十分危險的,因為依賴不同版本的庫可能會造成很多未知的風險玷室。怎么解決不同模塊之間對同一個庫的依賴版本一樣呢零蓉?Maven提供了優(yōu)雅的解決辦法,使用繼承機制以及dependencyManagement元素來解決這個問題穷缤。如果你在父模塊中配置dependencies敌蜂,那么所有的子模塊都自動繼承,不僅達到了依賴一致的目的津肛,還省了大段的代碼章喉,但這樣來做會存在問題的。比如B模塊需要spring-aop模塊身坐,但是C模塊不需要spring-aop模塊秸脱,如果用dependencies在父類中統(tǒng)一配置,C模塊中也會包含有spring-aop模塊部蛇,不符合我們的要求摊唇。但是用dependencyManagement就沒有這樣的問題。dependencyManagement只會影響現有依賴的配置涯鲁,但不會引入依賴巷查。這樣我們在父模塊中的配置可以更改如下所示:
<!-- dependencyManagement只會影響現有依賴的配置,但不會引入依賴抹腿。 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</dependencyManagement>
這段配置不會給任何子模塊引入依賴岛请,如果某個子模塊需要junit和log4j,只需要這樣配置即可:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
</dependencies>
在多模塊Maven項目中警绩,使用dependencyManagement能夠有效地幫我們維護依賴一致性崇败。
pluginManagement
上面介紹了在多模塊中對依賴庫的管理,接下來介紹下對插件的管理肩祥。與dependencyManagement類似后室,我們可以使用pluginManagement元素管理插件微渠。一個常見的用法就是我們希望項目所有模塊的使用compiler插件的時候,都是用java1.7咧擂,以及指定Java源文件編碼為UTF-8逞盆,這時可以在父模塊的POM中如下配置pluginManagement:
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
這段配置會被應用到所有子模塊的compiler插件中,因為Maven內置了與compiler插件與生命周期的綁定松申,因此子模塊不需要任何maven-compiler-plugin的配置了云芦。
Maven常用的幾個插件
Maven本質上是一個插件框架,它的核心并不執(zhí)行任何具體的構建任務贸桶,所有這些任務都交給插件來完成舅逸。下面說幾個常用的插件:
maven-compiler-plugin(編譯插件)
用來編譯Java代碼,在對Java代碼進行編譯的時候皇筛,可以指定使用哪個JDK的版本來進行編譯琉历,配置如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.7</source> <!-- 源代碼使用jdk1.7 -->
<target>1.7</target> <!-- 使用jvm1.7編譯目標代碼 -->
</configuration>
</plugin>
maven-resources-plugin(資源插件)
Maven區(qū)別對待Java代碼和資源文件,maven-resources-plugin則用來處理資源文件水醋。默認的主資源文件目錄是src/main/resources旗笔,很多時候會需要添加額外的資源文件目錄,這個時候就可以通過配置maven-resources-plugin來實現拄踪,配置如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>compile</phase> <!-- 與Maven編譯生命周期綁定在一起 -->
</execution>
</executions>
</plugin>
maven-surefire-plugin(測試插件)
Maven2/3中用于執(zhí)行測試的插件不是maven-test-plugin蝇恶,而是maven-surefire-plugin,其實在大部分情況下惶桐,只要你的測試類遵循通用的命令約定(以Test結尾撮弧,以TestCase結尾、或者Test開頭)姚糊,就幾乎不用知曉該插件的存在贿衍。但是當你想要跳過測試、排除某些測試類救恨、或者使用一些TestNG特性的時候贸辈,就要用到了maven-surefire-plugin的一些配置選項了,配置如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14</version>
<configuration>
<skipTests>true</skipTests> <!-- 跳過測試 -->
</configuration>
</plugin>
maven-clean-plugin(清除插件)
主要作用就是清理構建目錄下的全部內容忿薇,有些項目裙椭,構建時需要清理構建目錄以外的文件躏哩,比如指定的庫文件署浩,這時候就需要配置<filesets>來實現了,配置如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<!--<skip>true</skip>-->
<!--<failOnError>false</failOnError>-->
<!--當配置true時,只清理filesets里的文件,構建目錄中得文件不被清理.默認是flase.-->
<excludeDefaultDirectories>false</excludeDefaultDirectories>
<filesets>
<fileset>
<!--要清理的目錄位置-->
<directory>${basedir}/logs</directory>
<!--是否跟隨符號鏈接 (symbolic links)-->
<followSymlinks>false</followSymlinks>
</fileset>
</filesets>
</configuration>
</plugin>
maven-war-plugin(打包插件)
主要作用就是用來打包的扫尺,在打包的時候經常需要排除一些文件筋栋,就需要對warSourceExcludes進行配置了,配置如下所示:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<warSourceExcludes>WEB-INF/lib/**</warSourceExcludes>
</configuration>
</plugin>
總結
Maven是一個項目管理和自動化構建工具正驻,項目遵循約定優(yōu)于配置弊攘,這也是maven項目的一大特色抢腐。另外,maven本質上是一個插件框架襟交,它的核心不執(zhí)行任何具體的構建工作迈倍,全部都交給插件去執(zhí)行,maven插件是與maven生命周期綁定在一起的捣域。理解這些重要的核心點啼染,對于maven的使用會有很大的幫助。
參考文章
Maven入門介紹
http://www.oracle.com/technetwork/cn/community/java/apache-maven-getting-started-1-406235-zhs.html
http://www.oracle.com/technetwork/cn/community/java/apache-maven-getting-started-2-405568-zhs.html
https://maven.apache.org/what-is-maven.html
Maven常用插件
http://www.infoq.com/cn/news/2011/04/xxb-maven-7-plugin
http://www.infoq.com/cn/news/2011/05/xxb-maven-8-plugin