參考資料:http://my.oschina.net/zh119893/blog/276090
我們都知道Maven本質上是一個插件框架,它的核心並不執行任何具體的構建任務,所有這些任務都交給插件來完成。
例如編譯源代碼是由maven-compiler-plugin完成的。
進一步說,每個任務對應了一個插件目標(goal),每個插件會有一個或者多個目標。
例如maven-compiler-plugin的compile目標用來編譯位於src/main/java/
目錄下的主源碼,testCompile目標用來編譯位於src/test/java/
目錄下的測試源碼。
用戶可以通過兩種方式調用Maven插件目標。
第一種方式是將插件目標與生命周期階段(lifecycle phase)綁定,這樣用戶在命令行只是輸入生命周期階段而已。
例如Maven默認將maven-compiler-plugin的compile目標與compile生命周期階段綁定,因此命令mvn compile實際上是先定位到compile這一生命周期階段,然后再根據綁定關系調用maven-compiler-plugin的compile目標。
第二種方式是直接在命令行指定要執行的插件目標。
例如mvn archetype:generate 就表示調用maven-archetype-plugin的generate目標,這種帶冒號的調用方式與生命周期無關。
認識上述Maven插件的基本概念能幫助你理解Maven的工作機制,不過要想更高效率地使用Maven,了解一些常用的插件還是很有必要的,這可以幫助你避免一不小心重新發明輪子。
多年來Maven社區積累了大量的經驗,並隨之形成了一個成熟的插件生態圈。
Maven官方有兩個插件列表:
第一個列表的GroupId為org.apache.maven.plugins,這里的插件最為成熟,具體地址為:http://maven.apache.org/plugins/index.html。
第二個列表的GroupId為org.codehaus.mojo,這里的插件沒有那么核心,但也有不少十分有用,其地址為:http://mojo.codehaus.org/plugins.html。
接下來介紹一些常用的MAVEN插件
maven-antrun-plugin
http://maven.apache.org/plugins/maven-antrun-plugin/
maven-antrun-plugin能讓用戶在Maven項目中運行Ant任務。用戶可以直接在該插件的配置以Ant的方式編寫Target,然后交給該插件的run目標去執行。
在一些由Ant往Maven遷移的項目中,該插件尤其有用。
此外當你發現需要編寫一些自定義程度很高的任務,同時又覺得Maven不夠靈活時,也可以以Ant的方式實現之。maven-antrun-plugin的run目標通常與生命周期綁定運行。
maven-archetype-plugin
http://maven.apache.org/archetype/maven-archetype-plugin/
Archtype指項目的骨架,Maven初學者最開始執行的Maven命令可能就是mvn archetype:generate,這實際上就是讓maven-archetype-plugin生成一個很簡單的項目骨架,幫助開發者快速上手。
可能也有人看到一些文檔寫了mvn archetype:create,但實際上create目標已經被棄用了,取而代之的是generate目標,該目標使用交互式的方式提示用戶輸入必要的信息以創建項目,體驗更好。
maven-archetype-plugin還有一些其他目標幫助用戶自己定義項目原型,例如你由一個產品需要交付給很多客戶進行二次開發,你就可以為他們提供一個Archtype,幫助他們快速上手。
maven-assembly-plugin
http://maven.apache.org/plugins/maven-assembly-plugin/
maven-assembly-plugin的用途是制作項目分發包,該分發包可能包含了項目的可執行文件、源代碼、readme、平台腳本等等。
maven-assembly-plugin支持各種主流的格式如zip、tar.gz、jar和war等,具體打包哪些文件是高度可控的。
例如用戶可以按文件級別的粒度、文件集級別的粒度、模塊級別的粒度、以及依賴級別的粒度控制打包,此外,包含和排除配置也是支持的。
maven-assembly-plugin要求用戶使用一個名為assembly.xml
的元數據文件來表述打包,它的single目標可以直接在命令行調用,也可以被綁定至生命周期。
maven-dependency-plugin
http://maven.apache.org/plugins/maven-dependency-plugin/
maven-dependency-plugin最大的用途是幫助分析項目依賴
dependency:list能夠列出項目最終解析到的依賴列表
dependency:tree能進一步的描繪項目依賴樹
dependency:analyze可以告訴你項目依賴潛在的問題
如果你有直接使用到的卻未聲明的依賴,該目標就會發出警告。
maven-dependency-plugin還有很多目標幫助你操作依賴文件,例如dependency:copy-dependencies能將項目依賴從本地Maven倉庫復制到某個特定的文件夾下面。
maven-enforcer-plugin
http://maven.apache.org/plugins/maven-enforcer-plugin/
在一個稍大一點的組織或團隊中,你無法保證所有成員都熟悉Maven,那他們做一些比較愚蠢的事情就會變得很正常。
例如給項目引入了外部的SNAPSHOT依賴而導致構建不穩定,使用了一個與大家不一致的Maven版本而經常抱怨構建出現詭異問題。
maven-enforcer-plugin能夠幫助你避免之類問題,它允許你創建一系列規則強制大家遵守,包括設定Java版本、設定Maven版本、禁止某些依賴、禁止SNAPSHOT依賴。
只要在一個父POM配置規則,然后讓大家繼承,當規則遭到破壞的時候,Maven就會報錯。
除了標准的規則之外,你還可以擴展該插件,編寫自己的規則。maven-enforcer-plugin的enforce目標負責檢查規則,它默認綁定到生命周期的validate階段。
maven-help-plugin
http://maven.apache.org/plugins/maven-help-plugin/
maven-help-plugin是一個小巧的輔助工具。
最簡單的help:system可以打印所有可用的環境變量和Java系統屬性。
help:effective-pom和help:effective-settings最為有用,它們分別打印項目的有效POM和有效settings,有效POM是指合並了所有父POM(包括Super POM)后的XML,
當你不確定POM的某些信息從何而來時,就可以查看有效POM。
有效settings同理,特別是當你發現自己配置的settings.xml沒有生效時,就可以用help:effective-settings來驗證。
此外,maven-help-plugin的describe目標可以幫助你描述任何一個Maven插件的信息,還有all-profiles目標和active-profiles目標幫助查看項目的Profile。
maven-release-plugin
http://maven.apache.org/plugins/maven-release-plugin/
maven-release-plugin的用途是幫助自動化項目版本發布,它依賴於POM中的SCM信息。
release:prepare用來准備版本發布,具體的工作包括檢查是否有未提交代碼、檢查是否有SNAPSHOT依賴、升級項目的SNAPSHOT版本至RELEASE版本、為項目打標簽等等。
release:perform則是簽出標簽中的RELEASE源碼,構建並發布。版本發布是非常瑣碎的工作,它涉及了各種檢查,而且由於該工作僅僅是偶爾需要,因此手動操作很容易遺漏一些細節。
maven-release-plugin讓該工作變得非常快速簡便,不易出錯。maven-release-plugin的各種目標通常直接在命令行調用,因為版本發布顯然不是日常構建生命周期的一部分。
maven-resources-plugin
http://maven.apache.org/plugins/maven-resources-plugin/
為了使項目結構更為清晰,Maven區別對待Java代碼文件和資源文件,maven-compiler-plugin用來編譯Java代碼,maven-resources-plugin則用來處理資源文件。
默認的主資源文件目錄是src/main/resources
,很多用戶會需要添加額外的資源文件目錄,這個時候就可以通過配置maven-resources-plugin來實現。
此外,資源文件過濾也是Maven的一大特性,你可以在資源文件中使用${propertyName}形式的Maven屬性,然后配置maven-resources-plugin開啟對資源文件的過濾,
之后就可以針對不同環境通過命令行或者Profile傳入屬性的值,以實現更為靈活的構建。
maven-surefire-plugin
http://maven.apache.org/plugins/maven-surefire-plugin/
可能是由於歷史的原因,Maven 2/3中用於執行測試的插件不是maven-test-plugin,而是maven-surefire-plugin。
其實大部分時間內,只要你的測試類遵循通用的命令約定(以Test結尾、以TestCase結尾、或者以Test開頭),就幾乎不用知曉該插件的存在。
然而在當你想要跳過測試、排除某些測試類、或者使用一些TestNG特性的時候,了解maven-surefire-plugin的一些配置選項就很有用了。
例如 mvn test -Dtest=FooTest 這樣一條命令的效果是僅運行FooTest測試類,這是通過控制maven-surefire-plugin的test參數實現的。
build-helper-maven-plugin
http://mojo.codehaus.org/build-helper-maven-plugin/
Maven默認只允許指定一個主Java代碼目錄和一個測試Java代碼目錄,雖然這其實是個應當盡量遵守的約定,
但偶爾你還是會希望能夠指定多個源碼目錄(例如為了應對遺留項目),build-helper-maven-plugin的add-source目標就是服務於這個目的,
通常它被綁定到默認生命周期的generate-sources階段以添加額外的源碼目錄。需要強調的是,這種做法還是不推薦的,
因為它破壞了 Maven的約定,而且可能會遇到其他嚴格遵守約定的插件工具無法正確識別額外的源碼目錄。
build-helper-maven-plugin的另一個非常有用的目標是attach-artifact,
使用該目標你可以以classifier的形式選取部分項目文件生成附屬構件,並同時install到本地倉庫,也可以deploy到遠程倉庫。
exec-maven-plugin
http://mojo.codehaus.org/exec-maven-plugin/
exec-maven-plugin很好理解,顧名思義,它能讓你運行任何本地的系統程序,
在某些特定情況下,運行一個Maven外部的程序可能就是最簡單的問題解決方案,這就是exec:exec的用途,當然,該插件還允許你配置相關的程序運行參數。
除了exec目標之外,exec-maven-plugin還提供了一個java目標,該目標要求你提供一個mainClass參數,然后它能夠利用當前項目的依賴作為classpath,在同一個JVM中運行該mainClass。
有時候,為了簡單的演示一個命令行Java程序,你可以在POM中配置好exec-maven-plugin的相關運行參數,然后直接在命令運行 mvn exec:java 以查看運行效果。
jetty-maven-plugin
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin
在進行Web開發的時候,打開瀏覽器對應用進行手動的測試幾乎是無法避免的,這種測試方法通常就是將項目打包成war文件,然后部署到Web容器中,再啟動容器進行驗證,這顯然十分耗時。
為了幫助開發者節省時間,jetty-maven-plugin應運而生,它完全兼容 Maven項目的目錄結構,能夠周期性地檢查源文件,一旦發現變更后自動更新到內置的Jetty Web容器中。
做一些基本配置后(例如Web應用的contextPath和自動掃描變更的時間間隔),你只要執行 mvn jetty:run ,然后在IDE中修改代碼,代碼經IDE自動編譯后產生變更,
再由jetty-maven-plugin偵測到后更新至Jetty容器,這時你就可以直接測試Web頁面了。
需要注意的是,jetty-maven-plugin並不是宿主於Apache或Codehaus的官方插件,因此使用的時候需要額外的配置settings.xml
的pluginGroups元素,將org.mortbay.jetty這個pluginGroup加入。
versions-maven-plugin
http://mojo.codehaus.org/versions-maven-plugin/
很多Maven用戶遇到過這樣一個問題,當項目包含大量模塊的時候,為他們集體更新版本就變成一件煩人的事情,到底有沒有自動化工具能幫助完成這件事情呢?
(當然你可以使用sed之類的文本操作工具,不過不在本文討論范圍)答案是肯定的,versions-maven- plugin提供了很多目標幫助你管理Maven項目的各種版本信息。
例如最常用的,命令 mvn versions:set -DnewVersion=1.1-SNAPSHOT 就能幫助你把所有模塊的版本更新到1.1-SNAPSHOT。
該插件還提供了其他一些很有用的目標,display-dependency- updates能告訴你項目依賴有哪些可用的更新;
類似的display-plugin-updates能告訴你可用的插件更新;然后use- latest-versions能自動幫你將所有依賴升級到最新版本。
最后,如果你對所做的更改滿意,則可以使用 mvn versions:commit 提交,不滿意的話也可以使用 mvn versions:revert 進行撤銷。
小結
本文介紹了一些最常用的Maven插件,這里指的“常用”是指經常需要進行配置的插件,事實上我們用Maven的時候很多其它插件也是必須的,
例如默認的編譯插件maven-compiler-plugin和默認的打包插件maven-jar-plugin,但因為很少需要對它們進行配置,因此不在本文討論范圍。
了解常用的Maven插件能幫助你事倍功半地完成項目構建任務,反之你就可能會因為經常遇到一些難以解決的問題而感到沮喪。
本文介紹的插件基本能覆蓋大部分Maven用戶的日常使用需要,如果你真有非常特殊的需求,自行編寫一個Maven插件也不是難事,更何況還有這么多開放源代碼的插件供你參考。
一些常見例子
① maven-jetty-plugin
http://blog.sina.com.cn/s/blog_62b0363101012he0.html
http://stamen.iteye.com/blog/1933452
輸入:mvn jetty:run。這將在端口為8080的Jetty服務器上啟動你的項目。Jetty將持續運行,直到插件是明確停止。例如,按下<ctrl-c>,或使用mvn jetty:stop命令。
<build> <finalName>rop-sample</finalName> <plugins> <!-- jetty插件 --> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>6.1.5</version> <configuration> <webAppSourceDirectory>src/main/webapp</webAppSourceDirectory> <scanIntervalSeconds>3</scanIntervalSeconds> <contextPath>/</contextPath> <connectors> <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector"> <port>8088</port> </connector> </connectors> </configuration> </plugin> </plugins> </build>
② maven-compiler-plugin 編譯源代碼
在Maven項目下,我們需要配置"maven-compiler-plugin"的"encoding"參數
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <encoding>UTF8</encoding> </configuration> </plugin> </plugins>
需要在編譯和生成的時候使用不同的jdk版本
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.6</source> <target>1.7</target> </configuration> </plugin>
③ maven-war-plugin
打包war項目的時候排除某些web資源文件,這時就應該配置maven-war-plugin如下:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <webResources> <resource> <directory>src/main/webapp</directory> <excludes> <exclude>**/*.jpg</exclude> </excludes> </resource> </webResources> </configuration> </plugin>
④ maven-source-plugin 生成源碼包
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.2</version> <executions> <execution> <id>attach-sources</id> <phase>verify</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin>
<!-- 源代碼打包插件 -->
<plugin> <artifactId>maven-source-plugin</artifactId> <version>2.1</version> <configuration> <!-- <finalName>${project.build.name}</finalName> --> <attach>true</attach> <encoding>${project.build.sourceEncoding}</encoding> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin>
⑤ maven-javadoc-plugin 生成javadoc包
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>2.7</version> <executions> <execution> <id>attach-javadocs</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin>
⑥ maven-assembly-plugin
它支持各種打包文件格式,包括zip、tar.gz、tar.bz2等等,通過一個打包描述文件(該例中是src/main/assembly.xml),它能夠幫助用戶選擇具體打包哪些文件集合、依賴、模塊、和甚至本地倉庫文件,每個項的具體打包路徑用戶也能自由控制。如下就是對應上述需求的打包描述文件src/main/assembly.xml:
<assembly> <id>bin</id> <formats> <format>zip</format> </formats> <dependencySets> <dependencySet> <useProjectArtifact>true</useProjectArtifact> <outputDirectory>lib</outputDirectory> </dependencySet> </dependencySets> <fileSets> <fileSet> <outputDirectory>/</outputDirectory> <includes> <include>README.txt</include> </includes> </fileSet> <fileSet> <directory>src/main/scripts</directory> <outputDirectory>/bin</outputDirectory> <includes> <include>run.sh</include> <include>run.bat</include> </includes> </fileSet> </fileSets> </assembly>
最終生成一個zip格式的分發包,它包含如下的一個結構:
bin/
lib/
README.txt
最后,我們需要配置maven-assembly-plugin使用打包描述文件,並綁定生命周期階段使其自動執行打包操作:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.2.1</version> <configuration> <descriptors> <descriptor>src/main/assembly/assembly.xml</descriptor> </descriptors> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
運行mvn clean package之后,我們就能在target/目錄下得到名為hello-world-1.0-bin.zip的分發包了。
⑦ maven-surefire-plugin 打包時跳過單元測試
<plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.6</version> <configuration> <skip>true</skip> </configuration> </plugin>
mvn package -Dmaven.test.skip=true
如果單元測試中有輸出中文,eclipse的控制台里中文可能會變成亂碼輸出,也可以通過這個插件解決,參考配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.16</version> <configuration> <forkMode>once</forkMode> <argLine>-Dfile.encoding=UTF-8</argLine> </plugin>
⑧ maven-resource-plugin
<!-- 設置資源文件的編碼方式 -->
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.4.3</version> <executions> <execution> <phase>compile</phase> </execution> </executions> <configuration> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin>
把web項目的輸出copy到tomcat的webapp下
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.5</version> <executions> <execution> <id>deploy-website</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${server_home}/webapps/${project.build.finalName}</outputDirectory> <resources> <resource> <directory>${project.build.directory}/${project.build.finalName}</directory> </resource> </resources> </configuration> </execution> </executions> </plugin>
⑨ maven-dependency-plugin
自動拷貝jar包到target目錄
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-dependencies</id> <phase>compile</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <!-- ${project.build.directory}為Maven內置變量,缺省為target --> <outputDirectory>${project.build.directory}/lib</outputDirectory> <!-- 表示是否不包含間接依賴的包 --> <excludeTransitive>false</excludeTransitive> <!-- 表示復制的jar文件去掉版本信息 --> <stripVersion>true</stripVersion> </configuration> </execution> </executions> </plugin>
在部署war包時,需要將項目依賴的jar包,也打到war包中,因此就會用到上述插件
⑩ 在打包時,需要清空一些指定的目錄
在一個J2EE項目中,想使用mvn clean命令清除target里的內容的同時,也清除tomcat/webapp下的相應目錄,該怎么辦呢?
<plugin> <artifactId>maven-clean-plugin</artifactId> <configuration> <verbose>true</verbose> <filesets> <fileset> <directory>c:/a/b/c/</directory> </fileset> </filesets> </configuration> </plugin>
本例中,刪除的是c:/a/b/c/目錄.
當用戶在該maven項目中執行mvn clean后,除了刪除clean插件默認的
project.build.directory
project.build.outputDirectory
project.build.testOutputDirectory
project.reporting.outputDirectory
c:/a/b/c/
11、利用tomcat-maven-plugin插件將項目自動打包並部署到tomcat中
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <configuration> <server>tomcat6-manager</server> <path>/${project.build.name}</path> <url>http://localhost:8080/manager</url> <username>admin</username> <password>admin</password> </configuration> <executions> <execution> <phase>deploy</phase> <goals> <goal>deploy</goal> </goals> </execution> </executions> </plugin> </plugins>
path: 是指項目部署到tomcat后的項目名稱
url: 是指tomcat的manager訪問地址
server: 這個是tomcat服務名稱設置,需要配置maven的settings.xml文件,在servers節點中手動配置server,如下所示:
<server> <id>tomcat6-manager</id> <username>admin</username> <password>admin</password> </server>
12、利用cargo-maven2-plugin插件將項目自動打包並部署到tomcat中
cargo插件可以幫助你完成WAR包到服務器的部署及服務器的啟動和關閉等工作,方便,快速!
<plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.2.0</version> <configuration> <container> <containerId>${server_name}</containerId> <home>${server_home}</home> </container> <configuration> <type>existing</type> <home>${server_home}</home> <properties> <cargo.servlet.port>8088</cargo.servlet.port> </properties> </configuration> </configuration> </plugin>
注意,如果你的tomcat服務器的端口使用的不是默認的8080(如本例中的8088),則需要使用cargo.servlet.port參數將cargo的監聽端口也配置到tomcat的那個監聽端口(如本例中的8088),否則使用mvn cargo:run啟動的服務器會在120000毫秒(120秒)后自動關閉!
mvn cargo:start命令完成WAR包部署后,啟動服務器,然后會將服務器立即關掉;
mvn cargo:run命令完成WAR包部署后,啟動服務器,直到你Ctrl+C將服務器關掉;
mvn cargo:stop命令關閉服務器。
參考:http://cargo.codehaus.org/Maven2+plugin
<plugin> <!-- 指定插件名稱及版本號 --> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.2.3</version>
<!-- 插件的Tomcat6.x配置 --> <configuration> <!-- 容器的配置 --> <container> <!-- 指定服務器版本 --> <containerId>tomcat6x</containerId> <!-- 指定服務器的安裝目錄 --> <home>E:\Program Files\tomcat-6.0.32</home> </container> <!-- 具體的配置 --> <configuration> <!-- 部署模式:existing、standalone等 --> <type>existing</type> <!-- Tomcat的位置,即catalina.home --> <home>E:\Program Files\tomcat-6.0.32</home> <!-- 配置屬性 --> <properties> <!-- 管理地址 --> <cargo.tomcat.manager.url>http://localhost:8080/manager</cargo.tomcat.manager.url> <!-- Tomcat用戶名 --> <cargo.remote.username>admin</cargo.remote.username> <!-- Tomcat密碼 --> <cargo.remote.password>admin</cargo.remote.password> <!-- <cargo.jvmargs> -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787 </cargo.jvmargs> --> </properties> </configuration> </configuration> </plugin>