任何一個Maven項目都需要定義POM元素packaging(如果不寫則默認值為jar)。顧名思義,該元素決定了項目的打包方式。實際的情形中,如果你不聲明該元素,Maven會幫你生成一個JAR包;如果你定義該元素的值為war,那你會得到一個WAR包;如果定義其值為POM(比如是一個父模塊),那什么包都不會生成。你不需要了解具體的打包細節,你所需要做的就是告訴Maven,”我是個什么類型的項目“,這就是約定優于配置的力量。
為了更好的理解Maven的默認打包方式,我們不妨來看看簡單的聲明背后發生了什么,對一個jar項目執行mvn package操作,會看到如下的輸出:
--- maven-jar-plugin:2.3.1:jar (default-jar) @ git-demo ---
Building jar: /home/juven/git_juven/git-demo/target/git-demo-1.2-SNAPSHOT.jar
相比之下,對一個war項目執行mvn package操作,輸出是這樣的:
--- maven-war-plugin:2.1:war (default-war) @ webapp-demo ---
Packaging webapp
Assembling webapp [webapp-demo] in [/home/juven/git_juven/webapp-demo/target/webapp-demo-1.0-SNAPSHOT]
Processing war project
Copying webapp resources [/home/juven/git_juven/webapp-demo/src/main/webapp]
Webapp assembled in [90 msecs]
Building war: /home/juven/git_juven/webapp-demo/target/webapp-demo-1.0-SNAPSHOT.war
對應于同樣的package生命周期階段,Maven為jar項目調用了maven-jar-plugin,為war項目調用了maven-war-plugin,換言之,packaging直接影響Maven的構建生命周期。了解這一點非常重要,特別是當你需要自定義打包行為的時候,你就必須知道去配置哪個插件。一個常見的例子就是在打包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>
自定義格式包
實際的軟件項目常常會有更復雜的打包需求,例如我們可能需要為客戶提供一份產品的分發包,這個包不僅僅包含項目的字節碼文件,還得包含依賴以及相關腳本文件以方便客戶解壓后就能運行,此外分發包還得包含一些必要的文檔。這時項目的源碼目錄結構大致是這樣的:
pom.xml
src/main/java/
src/main/resources/
src/test/java/
src/test/resources/
src/main/scripts/
src/main/assembly/
README.txt
除了基本的pom.xml和一般Maven目錄之外,這里還有一個src/main/scripts/目錄,該目錄會包含一些腳本文件如run.sh和run.bat,src/main/assembly/會包含一個assembly.xml,這是打包的描述文件,稍后介紹,最后的README.txt是份簡單的文檔。
我們希望最終生成一個zip格式的分發包,它包含如下的一個結構:
bin/
lib/
README.txt
其中bin/目錄包含了可執行腳本run.sh和run.bat,lib/目錄包含了項目JAR包和所有依賴JAR,README.txt就是前面提到的文檔。
描述清楚需求后,我們就要搬出Maven最強大的打包插件:maven-assembly-plugin。它支持各種打包文件格式,包括zip、tar.gz、tar.bz2等等,通過一個打包描述文件(該例中是src/main/assembly.xml),它能夠幫助用戶選擇具體打包哪些文件集合、依賴、模塊、和甚至本地倉庫文件,每個項的具體打包路徑用戶也能自由控制。如下就是對應上述需求的打包描述文件src/main/assembly.xml:
<assembly>
<id>bin</id>
<formats>
<format>zip</format>
<format>war</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>
- 首先這個assembly.xml文件的id對應了其最終生成文件的classifier。
- 其次formats定義打包生成的文件格式,這里是zip。因此結合id我們會得到一個名為hello-world-1.0-bin.zip的文件。(假設artifactId為hello-world,version為1.0)??梢酝瑫r指定多個打包格式。
- dependencySets用來定義選擇依賴并定義最終打包到什么目錄,這里我們聲明的一個depenencySet默認包含所有所有依賴,而useProjectArtifact表示將項目本身生成的構件也包含在內,最終打包至輸出包內的lib路徑下(由outputDirectory指定)。
- fileSets允許用戶通過文件或目錄的粒度來控制打包。這里的第一個fileSet打包README.txt文件至包的根目錄下,第二個fileSet則將src/main/scripts下的run.sh和run.bat文件打包至輸出包的bin目錄下。更多配置參考這里
最后,我們需要配置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的分發包了。
要點:
默認打包插件:對應于同樣的package生命周期階段,Maven為jar項目調用了maven-jar-plugin,為war項目調用了maven-war-plugin。
定制化打包插件:maven-assembly-plugin支持定制化打包方式,通過一個打包描述文件src/main/assembly.xml。運行mvn clean package之后,就能在target目錄下得到所打的包。
參考:
http://www.infoq.com/cn/news/2011/06/xxb-maven-9-package
http://www.lxweimin.com/p/14bcb17b99e0