一、pom.xml
<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/maven-v4_0_0.xsd"> <!--父項目的座標。如果項目中沒有規定某個元素的值,那麼父項目中的對應值即爲項目的默認值。 座標包括group ID,artifact ID和 version。--> <parent> <!--被繼承的父項目的構件標識符--> <artifactId/> <!--被繼承的父項目的全球唯一標識符--> <groupId/> <!--被繼承的父項目的版本--> <version/> <!--父項目的pom.xml文件的相對路徑。相對路徑允許你選擇一個不同的路徑。默認值是../pom.xml。Maven首先在構建當前項目的地方尋找父項目的pom,其次在文件系統的這個位置(relativePath位置),然後在本地倉庫,最後在遠程倉庫尋找父項目的pom。--> <relativePath/> </parent> <!--聲明項目描述符遵循哪一個POM模型版本。模型本身的版本很少改變,雖然如此,但它仍然是必不可少的,這是爲了當Maven引入了新的特性或者其他模型變更的時候,確保穩定性。--> <modelVersion>4.0.0</modelVersion> <!--項目的全球唯一標識符,通常使用全限定的包名區分該項目和其他項目。並且構建時生成的路徑也是由此生成, 如com.mycompany.app生成的相對路徑爲:/com/mycompany/app--> <groupId>asia.banseon</groupId> <!--構件的標識符,它和group ID一起唯一標識一個構件。換句話說,你不能有兩個不同的項目擁有同樣的artifact ID和groupID;在某個特定的group ID下,artifact ID也必須是唯一的。構件是項目產生的或使用的一個東西,Maven爲項目產生的構件包括:JARs,源碼,二進制發佈和WARs等。--> <artifactId>banseon-maven2</artifactId> <!--項目產生的構件類型,例如jar、war、ear、pom。插件可以創建他們自己的構件類型,所以前面列的不是全部構件類型--> <packaging>jar</packaging> <!--項目當前版本,格式爲:主版本.次版本.增量版本-限定版本號--> <version>1.0-SNAPSHOT</version> <!--項目的名稱, Maven產生的文檔用--> <name>banseon-maven</name> <!--項目主頁的URL, Maven產生的文檔用--> <url>http://www.baidu.com/banseon</url> <!--項目的詳細描述, Maven 產生的文檔用。 當這個元素能夠用HTML格式描述時(例如,CDATA中的文本會被解析器忽略,就可以包含HTML標籤), 不鼓勵使用純文本描述。如果你需要修改產生的web站點的索引頁面,你應該修改你自己的索引頁文件,而不是調整這裏的文檔。--> <description>A maven project to study maven.</description> <!--描述了這個項目構建環境中的前提條件。--> <prerequisites> <!--構建該項目或使用該插件所需要的Maven的最低版本--> <maven/> </prerequisites> <!--項目的問題管理系統(Bugzilla, Jira, Scarab,或任何你喜歡的問題管理系統)的名稱和URL,本例爲 jira--> <issueManagement> <!--問題管理系統(例如jira)的名字,--> <system>jira</system> <!--該項目使用的問題管理系統的URL--> <url>http://jira.baidu.com/banseon</url> </issueManagement> <!--項目持續集成信息--> <ciManagement> <!--持續集成系統的名字,例如continuum--> <system/> <!--該項目使用的持續集成系統的URL(如果持續集成系統有web接口的話)。--> <url/> <!--構建完成時,需要通知的開發者/用戶的配置項。包括被通知者信息和通知條件(錯誤,失敗,成功,警告)--> <notifiers> <!--配置一種方式,當構建中斷時,以該方式通知用戶/開發者--> <notifier> <!--傳送通知的途徑--> <type/> <!--發生錯誤時是否通知--> <sendOnError/> <!--構建失敗時是否通知--> <sendOnFailure/> <!--構建成功時是否通知--> <sendOnSuccess/> <!--發生警告時是否通知--> <sendOnWarning/> <!--不贊成使用。通知發送到哪裏--> <address/> <!--擴展配置項--> <configuration/> </notifier> </notifiers> </ciManagement> <!--項目創建年份,4位數字。當產生版權信息時需要使用這個值。--> <inceptionYear/> <!--項目相關郵件列表信息--> <mailingLists> <!--該元素描述了項目相關的所有郵件列表。自動產生的網站引用這些信息。--> <mailingList> <!--郵件的名稱--> <name>Demo</name> <!--發送郵件的地址或鏈接,如果是郵件地址,創建文檔時,mailto: 鏈接會被自動創建--> <post>[email protected]</post> <!--訂閱郵件的地址或鏈接,如果是郵件地址,創建文檔時,mailto: 鏈接會被自動創建--> <subscribe>[email protected]</subscribe> <!--取消訂閱郵件的地址或鏈接,如果是郵件地址,創建文檔時,mailto: 鏈接會被自動創建--> <unsubscribe>[email protected]</unsubscribe> <!--你可以瀏覽郵件信息的URL--> <archive>http:/hi.baidu.com/banseon/demo/dev/</archive> </mailingList> </mailingLists> <!--項目開發者列表--> <developers> <!--某個項目開發者的信息--> <developer> <!--SCM裏項目開發者的唯一標識符--> <id>HELLO WORLD</id> <!--項目開發者的全名--> <name>banseon</name> <!--項目開發者的email--> <email>[email protected]</email> <!--項目開發者的主頁的URL--> <url/> <!--項目開發者在項目中扮演的角色,角色元素描述了各種角色--> <roles> <role>Project Manager</role> <role>Architect</role> </roles> <!--項目開發者所屬組織--> <organization>demo</organization> <!--項目開發者所屬組織的URL--> <organizationUrl>http://hi.baidu.com/banseon</organizationUrl> <!--項目開發者屬性,如即時消息如何處理等--> <properties> <dept>No</dept> </properties> <!--項目開發者所在時區, -11到12範圍內的整數。--> <timezone>-5</timezone> </developer> </developers> <!--項目的其他貢獻者列表--> <contributors> <!--項目的其他貢獻者。參見developers/developer元素--> <contributor> <name/><email/><url/><organization/><organizationUrl/><roles/><timezone/><properties/> </contributor> </contributors> <!--該元素描述了項目所有License列表。 應該只列出該項目的license列表,不要列出依賴項目的 license列表。如果列出多個license,用戶可以選擇它們中的一個而不是接受所有license。--> <licenses> <!--描述了項目的license,用於生成項目的web站點的license頁面,其他一些報表和validation也會用到該元素。--> <license> <!--license用於法律上的名稱--> <name>Apache 2</name> <!--官方的license正文頁面的URL--> <url>http://www.baidu.com/banseon/LICENSE-2.0.txt</url> <!--項目分發的主要方式: repo,可以從Maven庫下載 manual, 用戶必須手動下載和安裝依賴--> <distribution>repo</distribution> <!--關於license的補充信息--> <comments>A business-friendly OSS license</comments> </license> </licenses> <!--SCM(Source Control Management)標籤允許你配置你的代碼庫,供Maven web站點和其它插件使用。--> <scm> <!--SCM的URL,該URL描述了版本庫和如何連接到版本庫。欲知詳情,請看SCMs提供的URL格式和列表。該連接只讀。--> <connection> scm:svn:http://svn.baidu.com/banseon/maven/banseon/banseon-maven2-trunk(dao-trunk) </connection> <!--給開發者使用的,類似connection元素。即該連接不僅僅只讀--> <developerConnection> scm:svn:http://svn.baidu.com/banseon/maven/banseon/dao-trunk </developerConnection> <!--當前代碼的標籤,在開發階段默認爲HEAD--> <tag/> <!--指向項目的可瀏覽SCM庫(例如ViewVC或者Fisheye)的URL。--> <url>http://svn.baidu.com/banseon</url> </scm> <!--描述項目所屬組織的各種屬性。Maven產生的文檔用--> <organization> <!--組織的全名--> <name>demo</name> <!--組織主頁的URL--> <url>http://www.baidu.com/banseon</url> </organization> <!--構建項目需要的信息--> <build> <!--該元素設置了項目源碼目錄,當構建項目的時候,構建系統會編譯目錄裏的源碼。該路徑是相對於pom.xml的相對路徑。--> <sourceDirectory/> <!--該元素設置了項目腳本源碼目錄,該目錄和源碼目錄不同:絕大多數情況下,該目錄下的內容 會被拷貝到輸出目錄(因爲腳本是被解釋的,而不是被編譯的)。--> <scriptSourceDirectory/> <!--該元素設置了項目單元測試使用的源碼目錄,當測試項目的時候,構建系統會編譯目錄裏的源碼。該路徑是相對於pom.xml的相對路徑。--> <testSourceDirectory/> <!--被編譯過的應用程序class文件存放的目錄。--> <outputDirectory/> <!--被編譯過的測試class文件存放的目錄。--> <testOutputDirectory/> <!--使用來自該項目的一系列構建擴展--> <extensions> <!--描述使用到的構建擴展。--> <extension> <!--構建擴展的groupId--> <groupId/> <!--構建擴展的artifactId--> <artifactId/> <!--構建擴展的版本--> <version/> </extension> </extensions> <!--當項目沒有規定目標(Maven2 叫做階段)時的默認值--> <defaultGoal/> <!--這個元素描述了項目相關的所有資源路徑列表,例如和項目相關的屬性文件,這些資源被包含在最終的打包文件裏。--> <resources> <!--這個元素描述了項目相關或測試相關的所有資源路徑--> <resource> <!--描述了資源的目標路徑。該路徑相對target/classes目錄(例如${project.build.outputDirectory})。舉個例子,如果你想資源在特定的包裏(org.apache.maven.messages),你就必須該元素設置爲org/apache/maven/messages。然而,如果你只是想把資源放到源碼目錄結構裏,就不需要該配置。--> <targetPath/> <!--是否使用參數值代替參數名。參數值取自properties元素或者文件裏配置的屬性,文件在filters元素裏列出。--> <filtering/> <!--描述存放資源的目錄,該路徑相對POM路徑--> <directory/> <!--包含的模式列表,例如**/*.xml.--> <includes/> <!--排除的模式列表,例如**/*.xml--> <excludes/> </resource> </resources> <!--這個元素描述了單元測試相關的所有資源路徑,例如和單元測試相關的屬性文件。--> <testResources> <!--這個元素描述了測試相關的所有資源路徑,參見build/resources/resource元素的說明--> <testResource> <targetPath/><filtering/><directory/><includes/><excludes/> </testResource> </testResources> <!--構建產生的所有文件存放的目錄--> <directory/> <!--產生的構件的文件名,默認值是${artifactId}-${version}。--> <finalName/> <!--當filtering開關打開時,使用到的過濾器屬性文件列表--> <filters/> <!--子項目可以引用的默認插件信息。該插件配置項直到被引用時纔會被解析或綁定到生命週期。給定插件的任何本地配置都會覆蓋這裏的配置--> <pluginManagement> <!--使用的插件列表 。--> <plugins> <!--plugin元素包含描述插件所需要的信息。--> <plugin> <!--插件在倉庫裏的group ID--> <groupId/> <!--插件在倉庫裏的artifact ID--> <artifactId/> <!--被使用的插件的版本(或版本範圍)--> <version/> <!--是否從該插件下載Maven擴展(例如打包和類型處理器),由於性能原因,只有在真需要下載時,該元素才被設置成enabled。--> <extensions/> <!--在構建生命週期中執行一組目標的配置。每個目標可能有不同的配置。--> <executions> <!--execution元素包含了插件執行需要的信息--> <execution> <!--執行目標的標識符,用於標識構建過程中的目標,或者匹配繼承過程中需要合併的執行目標--> <id/> <!--綁定了目標的構建生命週期階段,如果省略,目標會被綁定到源數據裏配置的默認階段--> <phase/> <!--配置的執行目標--> <goals/> <!--配置是否被傳播到子POM--> <inherited/> <!--作爲DOM對象的配置--> <configuration/> </execution> </executions> <!--項目引入插件所需要的額外依賴--> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <!--任何配置是否被傳播到子項目--> <inherited/> <!--作爲DOM對象的配置--> <configuration/> </plugin> </plugins> </pluginManagement> <!--使用的插件列表--> <plugins> <!--參見build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/><artifactId/><version/><extensions/> <executions> <execution> <id/><phase/><goals/><inherited/><configuration/> </execution> </executions> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <goals/><inherited/><configuration/> </plugin> </plugins> </build> <!--在列的項目構建profile,如果被激活,會修改構建處理--> <profiles> <!--根據環境參數或命令行參數激活某個構建處理--> <profile> <!--構建配置的唯一標識符。即用於命令行激活,也用於在繼承時合併具有相同標識符的profile。--> <id/> <!--自動觸發profile的條件邏輯。Activation是profile的開啓鑰匙。profile的力量來自於它 能夠在某些特定的環境中自動使用某些特定的值;這些環境通過activation元素指定。activation元素並不是激活profile的唯一方式。--> <activation> <!--profile默認是否激活的標誌--> <activeByDefault/> <!--當匹配的jdk被檢測到,profile被激活。例如,1.4激活JDK1.4,1.4.0_2,而!1.4激活所有版本不是以1.4開頭的JDK。--> <jdk/> <!--當匹配的操作系統屬性被檢測到,profile被激活。os元素可以定義一些操作系統相關的屬性。--> <os> <!--激活profile的操作系統的名字--> <name>Windows XP</name> <!--激活profile的操作系統所屬家族(如 'windows')--> <family>Windows</family> <!--激活profile的操作系統體系結構 --> <arch>x86</arch> <!--激活profile的操作系統版本--> <version>5.1.2600</version> </os> <!--如果Maven檢測到某一個屬性(其值可以在POM中通過${名稱}引用),其擁有對應的名稱和值,Profile就會被激活。如果值 字段是空的,那麼存在屬性名稱字段就會激活profile,否則按區分大小寫方式匹配屬性值字段--> <property> <!--激活profile的屬性的名稱--> <name>mavenVersion</name> <!--激活profile的屬性的值--> <value>2.0.3</value> </property> <!--提供一個文件名,通過檢測該文件的存在或不存在來激活profile。missing檢查文件是否存在,如果不存在則激活 profile。另一方面,exists則會檢查文件是否存在,如果存在則激活profile。--> <file> <!--如果指定的文件存在,則激活profile。--> <exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</exists> <!--如果指定的文件不存在,則激活profile。--> <missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</missing> </file> </activation> <!--構建項目所需要的信息。參見build元素--> <build> <defaultGoal/> <resources> <resource> <targetPath/><filtering/><directory/><includes/><excludes/> </resource> </resources> <testResources> <testResource> <targetPath/><filtering/><directory/><includes/><excludes/> </testResource> </testResources> <directory/><finalName/><filters/> <pluginManagement> <plugins> <!--參見build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/><artifactId/><version/><extensions/> <executions> <execution> <id/><phase/><goals/><inherited/><configuration/> </execution> </executions> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <goals/><inherited/><configuration/> </plugin> </plugins> </pluginManagement> <plugins> <!--參見build/pluginManagement/plugins/plugin元素--> <plugin> <groupId/><artifactId/><version/><extensions/> <executions> <execution> <id/><phase/><goals/><inherited/><configuration/> </execution> </executions> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <goals/><inherited/><configuration/> </plugin> </plugins> </build> <!--模塊(有時稱作子項目) 被構建成項目的一部分。列出的每個模塊元素是指向該模塊的目錄的相對路徑--> <modules/> <!--發現依賴和擴展的遠程倉庫列表。--> <repositories> <!--參見repositories/repository元素--> <repository> <releases> <enabled/><updatePolicy/><checksumPolicy/> </releases> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <id/><name/><url/><layout/> </repository> </repositories> <!--發現插件的遠程倉庫列表,這些插件用於構建和報表--> <pluginRepositories> <!--包含需要連接到遠程插件倉庫的信息.參見repositories/repository元素--> <pluginRepository> <releases> <enabled/><updatePolicy/><checksumPolicy/> </releases> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <id/><name/><url/><layout/> </pluginRepository> </pluginRepositories> <!--該元素描述了項目相關的所有依賴。 這些依賴組成了項目構建過程中的一個個環節。它們自動從項目定義的倉庫中下載。要獲取更多信息,請看項目依賴機制。--> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> <!--不贊成使用. 現在Maven忽略該元素.--> <reports/> <!--該元素包括使用報表插件產生報表的規範。當用戶執行“mvn site”,這些報表就會運行。 在頁面導航欄能看到所有報表的鏈接。參見reporting元素--> <reporting> ...... </reporting> <!--參見dependencyManagement元素--> <dependencyManagement> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> </dependencyManagement> <!--參見distributionManagement元素--> <distributionManagement> ...... </distributionManagement> <!--參見properties元素--> <properties/> </profile> </profiles> <!--模塊(有時稱作子項目) 被構建成項目的一部分。列出的每個模塊元素是指向該模塊的目錄的相對路徑--> <modules/> <!--發現依賴和擴展的遠程倉庫列表。--> <repositories> <!--包含需要連接到遠程倉庫的信息--> <repository> <!--如何處理遠程倉庫裏發佈版本的下載--> <releases> <!--true或者false表示該倉庫是否爲下載某種類型構件(發佈版,快照版)開啓。 --> <enabled/> <!--該元素指定更新發生的頻率。Maven會比較本地POM和遠程POM的時間戳。這裏的選項是:always(一直),daily(默認,每日),interval:X(這裏X是以分鐘爲單位的時間間隔),或者never(從不)。--> <updatePolicy/> <!--當Maven驗證構件校驗文件失敗時該怎麼做:ignore(忽略),fail(失敗),或者warn(警告)。--> <checksumPolicy/> </releases> <!--如何處理遠程倉庫裏快照版本的下載。有了releases和snapshots這兩組配置,POM就可以在每個單獨的倉庫中,爲每種類型的構件採取不同的策略。例如,可能有人會決定只爲開發目的開啓對快照版本下載的支持。參見repositories/repository/releases元素--> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <!--遠程倉庫唯一標識符。可以用來匹配在settings.xml文件裏配置的遠程倉庫--> <id>banseon-repository-proxy</id> <!--遠程倉庫名稱--> <name>banseon-repository-proxy</name> <!--遠程倉庫URL,按protocol://hostname/path形式--> <url>http://192.168.1.169:9999/repository/</url> <!--用於定位和排序構件的倉庫佈局類型-可以是default(默認)或者legacy(遺留)。Maven 2爲其倉庫提供了一個默認的佈局;然而,Maven 1.x有一種不同的佈局。我們可以使用該元素指定佈局是default(默認)還是legacy(遺留)。--> <layout>default</layout> </repository> </repositories> <!--發現插件的遠程倉庫列表,這些插件用於構建和報表--> <pluginRepositories> <!--包含需要連接到遠程插件倉庫的信息.參見repositories/repository元素--> <pluginRepository> ...... </pluginRepository> </pluginRepositories> <!--該元素描述了項目相關的所有依賴。 這些依賴組成了項目構建過程中的一個個環節。它們自動從項目定義的倉庫中下載。要獲取更多信息,請看項目依賴機制。--> <dependencies> <dependency> <!--依賴的group ID--> <groupId>org.apache.maven</groupId> <!--依賴的artifact ID--> <artifactId>maven-artifact</artifactId> <!--依賴的版本號。 在Maven 2裏, 也可以配置成版本號的範圍。--> <version>3.8.1</version> <!--依賴類型,默認類型是jar。它通常表示依賴的文件的擴展名,但也有例外。一個類型可以被映射成另外一個擴展名或分類器。類型經常和使用的打包方式對應,儘管這也有例外。一些類型的例子:jar,war,ejb-client和test-jar。如果設置extensions爲 true,就可以在plugin裏定義新的類型。所以前面的類型的例子不完整。--> <type>jar</type> <!--依賴的分類器。分類器可以區分屬於同一個POM,但不同構建方式的構件。分類器名被附加到文件名的版本號後面。例如,如果你想要構建兩個單獨的構件成JAR,一個使用Java 1.4編譯器,另一個使用Java 6編譯器,你就可以使用分類器來生成兩個單獨的JAR構件。--> <classifier></classifier> <!--依賴範圍。在項目發佈過程中,幫助決定哪些構件被包括進來。欲知詳情請參考依賴機制。 - compile :默認範圍,用於編譯 - provided:類似於編譯,但支持你期待jdk或者容器提供,類似於classpath - runtime: 在執行時需要使用 - test: 用於test任務時使用 - system: 需要外在提供相應的元素。通過systemPath來取得 - systemPath: 僅用於範圍爲system。提供相應的路徑 - optional: 當項目自身被依賴時,標註依賴是否傳遞。用於連續依賴時使用--> <scope>test</scope> <!--僅供system範圍使用。注意,不鼓勵使用這個元素,並且在新的版本中該元素可能被覆蓋掉。該元素爲依賴規定了文件系統上的路徑。需要絕對路徑而不是相對路徑。推薦使用屬性匹配絕對路徑,例如${java.home}。--> <systemPath></systemPath> <!--當計算傳遞依賴時, 從依賴構件列表裏,列出被排除的依賴構件集。即告訴maven你只依賴指定的項目,不依賴項目的依賴。此元素主要用於解決版本衝突問題--> <exclusions> <exclusion> <artifactId>spring-core</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> <!--可選依賴,如果你在項目B中把C依賴聲明爲可選,你就需要在依賴於B的項目(例如項目A)中顯式的引用對C的依賴。可選依賴阻斷依賴的傳遞性。--> <optional>true</optional> </dependency> </dependencies> <!--不贊成使用. 現在Maven忽略該元素.--> <reports></reports> <!--該元素描述使用報表插件產生報表的規範。當用戶執行“mvn site”,這些報表就會運行。 在頁面導航欄能看到所有報表的鏈接。--> <reporting> <!--true,則,網站不包括默認的報表。這包括“項目信息”菜單中的報表。--> <excludeDefaults/> <!--所有產生的報表存放到哪裏。默認值是${project.build.directory}/site。--> <outputDirectory/> <!--使用的報表插件和他們的配置。--> <plugins> <!--plugin元素包含描述報表插件需要的信息--> <plugin> <!--報表插件在倉庫裏的group ID--> <groupId/> <!--報表插件在倉庫裏的artifact ID--> <artifactId/> <!--被使用的報表插件的版本(或版本範圍)--> <version/> <!--任何配置是否被傳播到子項目--> <inherited/> <!--報表插件的配置--> <configuration/> <!--一組報表的多重規範,每個規範可能有不同的配置。一個規範(報表集)對應一個執行目標 。例如,有1,2,3,4,5,6,7,8,9個報表。1,2,5構成A報表集,對應一個執行目標。2,5,8構成B報表集,對應另一個執行目標--> <reportSets> <!--表示報表的一個集合,以及產生該集合的配置--> <reportSet> <!--報表集合的唯一標識符,POM繼承時用到--> <id/> <!--產生報表集合時,被使用的報表的配置--> <configuration/> <!--配置是否被繼承到子POMs--> <inherited/> <!--這個集合裏使用到哪些報表--> <reports/> </reportSet> </reportSets> </plugin> </plugins> </reporting> <!--繼承自該項目的所有子項目的默認依賴信息。這部分的依賴信息不會被立即解析,而是當子項目聲明一個依賴(必須描述group ID和artifact ID信息),如果group ID和artifact ID以外的一些信息沒有描述,則通過group ID和artifact ID匹配到這裏的依賴,並使用這裏的依賴信息。--> <dependencyManagement> <dependencies> <!--參見dependencies/dependency元素--> <dependency> ...... </dependency> </dependencies> </dependencyManagement> <!--項目分發信息,在執行mvn deploy後表示要發佈的位置。有了這些信息就可以把網站部署到遠程服務器或者把構件部署到遠程倉庫。--> <distributionManagement> <!--部署項目產生的構件到遠程倉庫需要的信息--> <repository> <!--是分配給快照一個唯一的版本號(由時間戳和構建流水號)?還是每次都使用相同的版本號?參見repositories/repository元素--> <uniqueVersion/> <id>banseon-maven2</id> <name>banseon maven2</name> <url>file://${basedir}/target/deploy</url> <layout/> </repository> <!--構件的快照部署到哪裏?如果沒有配置該元素,默認部署到repository元素配置的倉庫,參見distributionManagement/repository元素--> <snapshotRepository> <uniqueVersion/> <id>banseon-maven2</id> <name>Banseon-maven2 Snapshot Repository</name> <url>scp://svn.baidu.com/banseon:/usr/local/maven-snapshot</url> <layout/> </snapshotRepository> <!--部署項目的網站需要的信息--> <site> <!--部署位置的唯一標識符,用來匹配站點和settings.xml文件裏的配置--> <id>banseon-site</id> <!--部署位置的名稱--> <name>business api website</name> <!--部署位置的URL,按protocol://hostname/path形式--> <url> scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web </url> </site> <!--項目下載頁面的URL。如果沒有該元素,用戶應該參考主頁。使用該元素的原因是:幫助定位那些不在倉庫裏的構件(由於license限制)。--> <downloadUrl/> <!--如果構件有了新的group ID和artifact ID(構件移到了新的位置),這裏列出構件的重定位信息。--> <relocation> <!--構件新的group ID--> <groupId/> <!--構件新的artifact ID--> <artifactId/> <!--構件新的版本號--> <version/> <!--顯示給用戶的,關於移動的額外信息,例如原因。--> <message/> </relocation> <!--給出該構件在遠程倉庫的狀態。不得在本地項目中設置該元素,因爲這是工具自動更新的。有效的值有:none(默認),converted(倉庫管理員從Maven 1 POM轉換過來),partner(直接從夥伴Maven 2倉庫同步過來),deployed(從Maven 2實例部署),verified(被覈實時正確的和最終的)。--> <status/> </distributionManagement> <!--以值替代名稱,Properties可以在整個POM中使用,也可以作爲觸發條件(見settings.xml配置文件裏activation元素的說明)。格式是<name>value</name>。--> <properties/> </project>
2、maven安裝
安裝環境
windowXP 32
下載地址
http://maven.apache.org/download.cgi
安裝包
apache-maven-3.2.3.zip
一、安裝
Step1 解壓縮
下載完成得到的是一個壓縮包文件,將它解壓縮後就可以使用了。
Step2 配置環境變量
Step3 驗證環境變量配置是否成功:mvn -v
二、 修改本地倉庫路徑
windows環境中,maven默認倉庫位置:C:\Documents and Settings\Administrator\.m2\repository
1、建立存放倉庫目錄:d:\java\maven\repos
2、在解壓縮目錄下找到 conf 文件夾並打開,找到 settings.xml 配置文件並打開它:複製到步驟1的目錄中。
3、修改兩處的settings.xml設置,在裏邊添加一行配置<localRepository>d:\java\maven\repos</localRepository>,將本地倉庫路徑指定到你自己想要指定的目錄當中。如下圖:
三、 查看中央倉庫路徑
1、在解壓縮目錄下找到 lib文件夾打開,查看到maven-model-builder-3.3.1.jar
2、maven-model-builder-3.3.1.jar\org\apache\maven\model\pom-4.0.0.xml中有網絡中央倉庫地址。
四、 執行第一次任務:mvn help:system
執行這個指令需要幾分鐘的時間才能完成,在這期間,你所要做的事情就是等待,直到出現,BUILD SUCCESS。
打開本地倉庫所在目錄,發現裏邊多了好些個文件夾,這是Maven從遠程中央倉庫download回來的文件
可以想象,伴隨着Maven的使用,以後這個目錄下的文件夾會變的越來越多,所佔用的磁盤空間也會變的越來越大,能達到好幾個G的大小,
所以在配置本地倉庫路徑的時候,需要給它預留幾個G大小的空間,這樣就沒什麼問題了。
1、生成項目骨架
命令:mvn archetype:generate -DgroupId=zttc.itat.maven -DartifactId=maven-ch01 -Dversion=0.0.1-SNAPSHOT
2、編譯
命令:maven compile
3、測試
命令:maven test
4、清空
命令:mvn clean目標文件夾清空
5、打包
命令:mvn package,打包該程序爲一個jar包或者war包。
6、安裝
命令:mvn install 安裝到本地倉庫中
7、測試輸出
命令:java -cp target/nameofjar.jar javamain
其中-cp命令是用於運行一個jar包並指定該jar包的main方法所在類。nameofjar.jar是指項目在target目錄下打包項目生成的jar包,替換爲自己的jar包名即可,另外javamain是指該jar的main方法所在類,包含該類的包名和類名。
事例:java -cp target/maven-ch01-0.0.1-SNAPSHOT.jar zttc.itat.maven.HelloMaven
maven有三套生命週期
1.clean 清理項目
2.default 構建項目
3.site 建立項目站點
每套生命週期都包含了一些階段,這些階段是有序的,後面的階段依賴前面的階段,
以clean生命週期爲例,它包括了pre-clean,clean和post-clean三個階段,當我們調用pre-clean的時候, 只會執行pre-clean階段;
當調用clean的時候,pre-clean和clean階段會以順序執行;當調用post-clean的時候,pre-clean,clean和post-clean三個階段會以順序執行。
這三套生命週期是相互獨立的,可以僅僅調用clean聲明週期的某個階段, 或者調用default生命週期的某個階段,而不會對其他生命週期產生任何影響。
clean生命週期共包含了三個階段:
pre-clean 執行一些需要在clean之前完成的工作
clean 移除所有上一次構建生成的文件
post-clean 執行一些需要在clean之後立刻完成的工作
default生命週期包含的階段:
validate
initialize
generate-sources
process-sources
generate-resources
process-resources 複製並處理資源文件,至目標目錄,準備打包。
compile 編譯項目的源代碼。
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources 複製並處理資源文件,至目標測試目錄。
test-compile 編譯測試源代碼。
process-test-classes
test 使用合適的單元測試框架運行測試。這些測試代碼不會被打包或部署。
prepare-package
package 接受編譯好的代碼,打包成可發佈的格式,如 JAR 。
pre-integration-test
integration-test
post-integration-test
verify
install 將包安裝至本地倉庫,以讓其它項目依賴。
deploy 將最終的包複製到遠程的倉庫,以讓其它開發人員與項目共享。
site生命週期的各個階段:
pre-site 執行一些需要在生成站點文檔之前完成的工作
site 生成項目的站點文檔
post-site 執行一些需要在生成站點文檔之後完成的工作,並且爲部署做準備
site-deploy 將生成的站點文檔部署到特定的服務器上
組合階段執行:
mvn clean 調用的clean生命週期的clean階段,實際執行的是pre-clean和clean階段。
mvn test 執行的是default生命週期的test階段, 實際執行的是validate到test階段。
mvn clean package clean生命週期的pre-clean,clean階段和 default生命週期的從validate到package階段。
文件存放位置
全局配置: ${M2_HOME}/conf/settings.xml
用戶配置: ${user.home}/.m2/settings.xml
note:用戶配置優先於全局配置。${user.home} 和和所有其他系統屬性只能在3.0+版本上使用。請注意windows和Linux使用變量的區別。
settings.xml詳解
聲明規範
<?xml version="1.0" encoding="UTF-8"?> <settings 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/settings-1.0.0.xsd">
localRepository
<!-- 本地倉庫的路徑。默認值爲${user.home}/.m2/repository。 --> <localRepository>usr/local/maven</localRepository>
interactiveMode
<!--Maven是否需要和用戶交互以獲得輸入。如果Maven需要和用戶交互以獲得輸入,則設置成true,反之則應爲false。默認爲true。--> <interactiveMode>true</interactiveMode>
usePluginRegistry
<!--Maven是否需要使用plugin-registry.xml文件來管理插件版本。如果需要讓Maven使用文件${user.home}/.m2/plugin-registry.xml來管理插件版本,則設爲true。默認爲false。--> <usePluginRegistry>false</usePluginRegistry>
offline
<!--表示Maven是否需要在離線模式下運行。如果構建系統需要在離線模式下運行,則爲true,默認爲false。當由於網絡設置原因或者安全因素,構建服務器不能連接遠程倉庫的時候,該配置就十分有用。 --> <offline>false</offline>
pluginGroups
<!--當插件的組織Id(groupId)沒有顯式提供時,供搜尋插件組織Id(groupId)的列表。該元素包含一個pluginGroup元素列表,每個子元素包含了一個組織Id(groupId)。當我們使用某個插件,並且沒有在命令行爲其提供組織Id(groupId)的時候,Maven就會使用該列表。默認情況下該列表包含了org.apache.maven.plugins和org.codehaus.mojo --> <pluginGroups> <!--plugin的組織Id(groupId) --> <pluginGroup>org.codehaus.mojo</pluginGroup> </pluginGroups>
proxies
<!--用來配置不同的代理,多代理profiles 可以應對筆記本或移動設備的工作環境:通過簡單的設置profile id就可以很容易的更換整個代理配置。 --> <proxies> <!--代理元素包含配置代理時需要的信息--> <proxy> <!--代理的唯一定義符,用來區分不同的代理元素。--> <id>myproxy</id> <!--該代理是否是激活的那個。true則激活代理。當我們聲明瞭一組代理,而某個時候只需要激活一個代理的時候,該元素就可以派上用處。 --> <active>true</active> <!--代理的協議。 協議://主機名:端口,分隔成離散的元素以方便配置。--> <protocol>http</protocol> <!--代理的主機名。協議://主機名:端口,分隔成離散的元素以方便配置。 --> <host>proxy.somewhere.com</host> <!--代理的端口。協議://主機名:端口,分隔成離散的元素以方便配置。 --> <port>8080</port> <!--代理的用戶名,用戶名和密碼錶示代理服務器認證的登錄名和密碼。 --> <username>proxyuser</username> <!--代理的密碼,用戶名和密碼錶示代理服務器認證的登錄名和密碼。 --> <password>somepassword</password> <!--不該被代理的主機名列表。該列表的分隔符由代理服務器指定;例子中使用了豎線分隔符,使用逗號分隔也很常見。--> <nonProxyHosts>*.google.com|ibiblio.org</nonProxyHosts> </proxy> </proxies>
servers
<!--配置服務端的一些設置。一些設置如安全證書不應該和pom.xml一起分發。這種類型的信息應該存在於構建服務器上的settings.xml文件中。--> <servers> <!--服務器元素包含配置服務器時需要的信息 --> <server> <!--這是server的id(注意不是用戶登陸的id),該id與distributionManagement中repository元素的id相匹配。--> <id>server001</id> <!--鑑權用戶名。鑑權用戶名和鑑權密碼錶示服務器認證所需要的登錄名和密碼。 --> <username>my_login</username> <!--鑑權密碼 。鑑權用戶名和鑑權密碼錶示服務器認證所需要的登錄名和密碼。密碼加密功能已被添加到2.1.0 +。詳情請訪問密碼加密頁面--> <password>my_password</password> <!--鑑權時使用的私鑰位置。和前兩個元素類似,私鑰位置和私鑰密碼指定了一個私鑰的路徑(默認是${user.home}/.ssh/id_dsa)以及如果需要的話,一個密語。將來passphrase和password元素可能會被提取到外部,但目前它們必須在settings.xml文件以純文本的形式聲明。 --> <privateKey>${usr.home}/.ssh/id_dsa</privateKey> <!--鑑權時使用的私鑰密碼。--> <passphrase>some_passphrase</passphrase> <!--文件被創建時的權限。如果在部署的時候會創建一個倉庫文件或者目錄,這時候就可以使用權限(permission)。這兩個元素合法的值是一個三位數字,其對應了unix文件系統的權限,如664,或者775。 --> <filePermissions>664</filePermissions> <!--目錄被創建時的權限。 --> <directoryPermissions>775</directoryPermissions> </server> </servers>
mirrors
<!--爲倉庫列表配置的下載鏡像列表。高級設置請參閱鏡像設置頁面 --> <mirrors> <!--給定倉庫的下載鏡像。 --> <mirror> <!--該鏡像的唯一標識符。id用來區分不同的mirror元素。 --> <id>planetmirror.com</id> <!--鏡像名稱 --> <name>PlanetMirror Australia</name> <!--該鏡像的URL。構建系統會優先考慮使用該URL,而非使用默認的服務器URL。 --> <url>http://downloads.planetmirror.com/pub/maven2</url> <!--被鏡像的服務器的id。例如,如果我們要設置了一個Maven中央倉庫(http://repo.maven.apache.org/maven2/)的鏡像,就需要將該元素設置成central。這必須和中央倉庫的id central完全一致。--> <mirrorOf>central</mirrorOf> </mirror> </mirrors>
profiles
<!--根據環境參數來調整構建配置的列表。settings.xml中的profile元素是pom.xml中profile元素的裁剪版本。它包含了id,activation, repositories, pluginRepositories和 properties元素。這裏的profile元素只包含這五個子元素是因爲這裏只關心構建系統這個整體(這正是settings.xml文件的角色定位),而非單獨的項目對象模型設置。如果一個settings中的profile被激活,它的值會覆蓋任何其它定義在POM中或者profile.xml中的帶有相同id的profile。 --> <profiles> <!--根據環境參數來調整的構件的配置--> <profile> <!--該配置的唯一標識符。 --> <id>test</id>
Activation
<!--自動觸發profile的條件邏輯。Activation是profile的開啓鑰匙。如POM中的profile一樣,profile的力量來自於它能夠在某些特定的環境中自動使用某些特定的值;這些環境通過activation元素指定。activation元素並不是激活profile的唯一方式。settings.xml文件中的activeProfile元素可以包含profile的id。profile也可以通過在命令行,使用-P標記和逗號分隔的列表來顯式的激活(如,-P test)。--> <activation> <!--profile默認是否激活的標識--> <activeByDefault>false</activeByDefault> <!--當匹配的jdk被檢測到,profile被激活。例如,1.4激活JDK1.4,1.4.0_2,而!1.4激活所有版本不是以1.4開頭的JDK。--> <jdk>1.5</jdk> <!--當匹配的操作系統屬性被檢測到,profile被激活。os元素可以定義一些操作系統相關的屬性。--> <os> <!--激活profile的操作系統的名字 --> <name>Windows XP</name> <!--激活profile的操作系統所屬家族(如 'windows') --> <family>Windows</family> <!--激活profile的操作系統體系結構 --> <arch>x86</arch> <!--激活profile的操作系統版本--> <version>5.1.2600</version> </os> <!--如果Maven檢測到某一個屬性(其值可以在POM中通過${name}引用),其擁有對應的name = 值,Profile就會被激活。如果值字段是空的,那麼存在屬性名稱字段就會激活profile,否則按區分大小寫方式匹配屬性值字段--> <property> <!--激活profile的屬性的名稱--> <name>mavenVersion</name> <!--激活profile的屬性的值 --> <value>2.0.3</value> </property> <!--提供一個文件名,通過檢測該文件的存在或不存在來激活profile。missing檢查文件是否存在,如果不存在則激活profile。另一方面,exists則會檢查文件是否存在,如果存在則激活profile。--> <file> <!--如果指定的文件存在,則激活profile。 --> <exists>${basedir}/file2.properties</exists> <!--如果指定的文件不存在,則激活profile。--> <missing>${basedir}/file1.properties</missing> </file> </activation>
Properties
<!--對應profile的擴展屬性列表。Maven屬性和Ant中的屬性一樣,可以用來存放一些值。這些值可以在POM中的任何地方使用標記${X}來使用,這裏X是指屬性的名稱。屬性有五種不同的形式,並且都能在settings.xml文件中訪問。 1. env.X: 在一個變量前加上"env."的前綴,會返回一個shell環境變量。例如,"env.PATH"指代了$path環境變量(在Windows上是%PATH%)。 2. project.x:指代了POM中對應的元素值。例如: <project><version>1.0</version></project>通過${project.version}獲得version的值。 3. settings.x: 指代了settings.xml中對應元素的值。例如:<settings><offline>false</offline></settings>通過 ${settings.offline}獲得offline的值。 4. Java System Properties: 所有可通過java.lang.System.getProperties()訪問的屬性都能在POM中使用該形式訪問,例如 ${java.home}。 5. x: 在<properties/>元素中,或者外部文件中設置,以${someVar}的形式使用。 --> <properties> <user.install>${user.home}/our-project</user.install> </properties> note:如果該profile被激活,則可以再POM中使用${user.install}。
Repositories
<!--遠程倉庫列表,它是Maven用來填充構建系統本地倉庫所使用的一組遠程項目。 --> <repositories> <!--包含需要連接到遠程倉庫的信息 --> <repository> <!--遠程倉庫唯一標識--> <id>codehausSnapshots</id> <!--遠程倉庫名稱 --> <name>Codehaus Snapshots</name> <!--如何處理遠程倉庫裏發佈版本的下載--> <releases> <!--true或者false表示該倉庫是否爲下載某種類型構件(發佈版,快照版)開啓。 --> <enabled>false</enabled> <!--該元素指定更新發生的頻率。Maven會比較本地POM和遠程POM的時間戳。這裏的選項是:always(一直),daily(默認,每日),interval:X(這裏X是以分鐘爲單位的時間間隔),或者never(從不)。 --> <updatePolicy>always</updatePolicy> <!--當Maven驗證構件校驗文件失敗時該怎麼做-ignore(忽略),fail(失敗),或者warn(警告)。--> <checksumPolicy>warn</checksumPolicy> </releases> <!--如何處理遠程倉庫裏快照版本的下載。有了releases和snapshots這兩組配置,POM就可以在每個單獨的倉庫中,爲每種類型的構件採取不同的策略。例如,可能有人會決定只爲開發目的開啓對快照版本下載的支持。參見repositories/repository/releases元素--> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <!--遠程倉庫URL,按protocol://hostname/path形式 --> <url>http://snapshots.maven.codehaus.org/maven2</url> <!--用於定位和排序構件的倉庫佈局類型-可以是default(默認)或者legacy(遺留)。Maven 2爲其倉庫提供了一個默認的佈局;然而,Maven 1.x有一種不同的佈局。我們可以使用該元素指定佈局是default(默認)還是legacy(遺留)。 --> <layout>default</layout> </repository> </repositories> <!--發現插件的遠程倉庫列表。倉庫是兩種主要構件的家。第一種構件被用作其它構件的依賴。這是中央倉庫中存儲的大部分構件類型。另外一種構件類型是插件。Maven插件是一種特殊類型的構件。由於這個原因,插件倉庫獨立於其它倉庫。pluginRepositories元素的結構和repositories元素的結構類似。每個pluginRepository元素指定一個Maven可以用來尋找新插件的遠程地址。--> <pluginRepositories> <!--包含需要連接到遠程插件倉庫的信息.參見profiles/profile/repositories/repository元素的說明--> <pluginRepository> <releases> <enabled/><updatePolicy/><checksumPolicy/> </releases> <snapshots> <enabled/><updatePolicy/><checksumPolicy/> </snapshots> <id/><name/><url/><layout/> </pluginRepository> </pluginRepositories> </profile> </profiles>
activeProfiles
<!--手動激活profiles的列表,按照profile被應用的順序定義activeProfile。 該元素包含了一組activeProfile元素,每個activeProfile都含有一個profile id。任何在activeProfile中定義的profile id,不論環境設置如何,其對應的 profile都會被激活。如果沒有匹配的profile,則什麼都不會發生。例如,env-test是一個activeProfile,則在pom.xml(或者profile.xml)中對應id的profile會被激活。如果運行過程中找不到這樣一個profile,Maven則會像往常一樣運行。 --> <activeProfiles> <!-- --> <activeProfile>env-test</activeProfile> </activeProfiles> </settings>
說明:
1、使用-選項時,和後面的參數之間可以不要空格。而使用--選項時,和後面的參數之 間必須有空格。如下面的例子:
$ mvn help:describe -Dcmd=compiler:compile
$ mvn install --define maven.test.skip=true
2、有些命令行選項是從Maven2.1纔有的。
3、更多命令行選項請查看mvn -h
定義屬性
-D,--define<arg> 定義系統屬性
這是最常用到的定製Maven插件行爲的選項。
獲得幫助
-h,--help 顯示幫助信息
如果你要尋找特定插件的可用目標和參數信息,請參考Maven Help 插件。
使用構建剖面(profile)
要從命令行激活一個或多個構建剖面,使用下面的選項:
-P,--activate-profiles<arg> 被激活的,用逗號分隔的剖面列表
顯示版本信息
要顯示Maven版本信息,在命令行裏,使用下面選項中的一個。
-V,--show-version 顯示版本信息後繼續執行Maven其他目標。
-v,--version 顯示版本信息。
這兩個選項輸出相同的版本信息,但-v選項在打印版本信息後會中斷Maven處理。如果你想讓Maven版本信息出現在構建輸出的開始處,你應該使用-V選項。如果你正在持續構建環境裏運行Maven,並且你需要知道特定構建使用了哪個Maven版本,-V選項就可以派上用場。
離線模式運行
-o,--offline 離線模式工作
該參數可以阻止通過網絡更新插件或依賴。
使用定製的POM或定製的Settings文件
如果你不喜歡pom.xml文件名、用戶相關的Maven配置文件的位置或者全局配置文件的位置,你可以通過下面的選項定製這些參數。
-f, --file <file> 強制使用備用的POM文件
-s,--settings <arg> 用戶配置文件的備用路徑
-gs, --global-settings <file> 全局配置文件的備用路徑
加密密碼
下面的命令允許你使用Maven加密密碼,然後存儲到Maven settings文件裏:
-emp,--encrypt-master-password <password> 加密主安全密碼
-ep,--encrypt-password <password> 加密服務器密碼
失敗處理
下面的選項控制,在多模塊項目構建的中間階段,Maven如何應對構建失敗。
-fae, --fail-at-end 僅影響構建結果,允許不受影響的構建繼續
-ff, --fail-fast 遇到構建失敗就停下來
-fn,--fail-never 無論項目結果如何,構建從不失敗
-fn 和 -fae選項對於使用持續集成工具(例如Hunson)的多模塊構建非常有用。 -ff 選項對於運行交互構建的開發者非常有用,因爲開發者在開發週期中想得到快速的反饋。
控制Maven的日誌級別
如果你想控制Maven的日誌級別,你可以使用下面三個命令行選項:
-e, --errors 產生執行錯誤相關消息
-X, --debug 產生執行調試信息
-q, --quiet 僅僅顯示錯誤
只有出現錯誤或問題,-q 選項纔打印一條消息。-X 選項會打印大量的調試日誌消息,這個選項主要被Maven開發者和Maven插件開發者用來診斷在開發過程中碰到的Maven代碼問題。如果你想診斷依賴或路徑問題,-X 選項也非常有用。如果你是Maven開發者,或者你需要診斷Maven插件的一個錯誤,那麼-e選項就會派上用場。如果你想報告Maven或Maven插件的一個未預料到的問題,你應該傳遞-X 和 -e命令行選項。
用批處理方式運行Maven
要在批處理模式下運行Maven,使用下面的選項:
-B, --batch-mode 在非交互(批處理)模式下運行
如果你需要在非交互、持續集成環境下運行Manve,必須要使用批處理模式。在非交互模式下運行,當Mven需要輸入時,它不會停下來接受用戶的輸入,而是使用合理的默認值。
下載和驗證依賴
下面的命令行選項會影響Maven和遠程倉庫的交互以及Maven如何驗證下載的構件:
-C, --strict-checksums 如果校驗碼不匹配的話,構建失敗
-c, --lax-checksums 如果校驗碼不匹配的話,產生告警
-U, --update-snapshots 在遠程倉管更新發布版本或快照版本時,強制更新。
如果你關注安全,你就想帶 -C選項運行Maven。Maven倉庫爲每個存儲在倉庫裏的構件維護一個MD5 和 SHA1 校驗碼。如果構件的校驗碼不匹配下載的構件,Maven默認被配置成告警終端用戶。如果傳遞-C 選項,當遇到帶着錯誤校驗碼的構件,會引起Maven構建失敗。如果你想確保Maven檢查所有快照依賴的最新版本,-U選項非常有用。
控制插件更新
下面的命令行選項告訴Maven,它將如何從遠程倉庫更新(或不更新)Maven插件:
-npu,--no-plugin-updates 對任何相關的註冊插件,不進行最新檢查。使用該選項使Maven表現出穩定行爲,該穩定行爲基於本地倉庫當前可用的所有插件版本。
-cpu, --check-plugin-updates 對任何相關的註冊插件,強制進行最新檢查。強制Maven檢查Maven插件的最新發布版本,即使在你的項目POM裏明確規定了Maven插件版本,還是會強制更新。
-up, --update-plugins cpu的同義詞.
下面的命令行選項影響Maven從遠處倉庫下載插件的方式:
-npr, --no-plugin-registry 對插件版本不使用~/.m2/plugin-registry.xml 裏的配置。
-npr 命令行選項告訴Maven不要參考插件註冊表。欲瞭解關於插件註冊表的更多信息,去這裏:http://maven.apache.org/guides/introduction/introduction-to-plugin-registry.html.
Maven內置變量說明:
- ${basedir} 項目根目錄(即pom.xml文件所在目錄)
- ${project.build.directory} 構建目錄,缺省爲target目錄
- ${project.build.outputDirectory} 構建過程輸出目錄,缺省爲target/classes
- ${project.build.finalName} 產出物名稱,缺省爲${project.artifactId}-${project.version}
- ${project.packaging} 打包類型,缺省爲jar
- ${project.xxx} 當前pom文件的任意節點的內容
- ${env.xxx} 獲取系統環境變量。例如,"env.PATH"指代了$path環境變量(在Windows上是%PATH%)。
- ${settings.xxx} 指代了settings.xml中對應元素的值。例如:<settings><offline>false</offline></settings>通過 ${settings.offline}獲得offline的值。
- Java System Properties: 所有可通過java.lang.System.getProperties()訪問的屬性都能在POM中使用,例如 ${JAVA_HOME}。
座標是Maven最基本的概念,它就像每個構件的身份證號碼,有了它我們就可以在數以千萬計的構件中定位任何一個我們感興趣的構件。舉個最簡單的例子,如果沒有座標,使用JUnit的時候,用戶就需要去下載依賴jar包,用依賴的方式,簡單配置使用如junit:junit:4.8.2就可以了。這裏第一個junit是groupId,第二個junit是artifactId,4.8.2是version。
Maven的很多其他核心機制都依賴於座標,其中最顯著的就是倉庫和依賴管理。對於倉庫來說,有了座標就知道在什麼位置存儲構件的內容,例如junit:junit:4.8.2就對應倉庫中的路徑/junit/junit/4.8.2/junit-4.8.2.pom
和/junit/junit/4.8.2/junit-4.8.2.jar
這樣的文件,讀者可以直接訪問中央倉庫地址看到這樣的倉庫佈局,或者瀏覽本地倉庫目錄~/.m2/repository/
以獲得直觀的體驗。
依賴的配置也是完全基於座標的.
有了正確的座標,Maven才能夠在正確的位置找到依賴文件並使用,這裏值爲test的scope是用來控制該依賴只在測試時可用,與座標無關。
正因爲座標是Maven核心的核心,因此規劃正確的座標至關重要,如果你使用了模糊不清的座標,那麼你的用戶就很難找到你的構件,或者即使找到了,也容易寫錯。錯誤的使用座標,還會造成衝突,如果你也使用junit這樣的groupId,那會發生什麼
Maven 座標有groupId,artifactId,packaging,version,classifier
<groupId>com.x</groupId> <artifactId>helloworld-1</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version>
(1).groupId,定義當前maven項目隸屬的實際項目。首先,maven項目和實際項目不一定是一對一的關係。比如SpringFramework這一實際項目,其對應的maven項目會有很 多,如: spring-core,spring-context等。這是由於maven中模塊的概念,因此,一個實際項目往往會被劃分成很多模塊。其次,groupId不應該對應項目隸屬的組織或公司。原因很簡單,一個組織下會有很多個實際項目,如果groupId只定義到組織級別,而後面我們會看到,artifactId只能定義maven項目(模塊),那麼實際項目這個層將難以定義。最後,groupId的表示方式與java包名的表示方式類似,通常與域名反向一一對應。
(2).artifactId,該元素定義實際項目中的一個maven項目(模塊),推薦的做法是使用實際項目名稱作爲artifactId前綴,這樣做的好處是方便尋找實際構件。在默認情況下,maven生成的構件,其文件名會以artifactId作爲開頭,如:helloworld-1-0.0.1-SNAPSHOT.jar,使用實際項目名稱作爲前綴之後,就能方便從一個lib文件夾中找到某個項目的一組構件。。
(3).version,該元素定義maven項目當前所處的版本,如:helloworld-1-0.0.1-SNAPSHOT.jar的版本是0.0.1。需要注意的是,maven定義了一套完整的版本規範,以及快照(SNAPSHOT)的概念。
(4).packaging, 定義了maven項目的打包方式。默認值爲jar,可取值:ejb / ejb3 /jar / par / rar / war。
(5).classifier,該元素用來幫助定義構建輸出的一些附屬構件。附屬構件與主構件對應,如上例中的主構件是: nexus-indexer-2.0.0.jar,該項目可能還會通過使用一些插件生成如:helloworld-1-0.0.1-SNAPSHOT-javadoc.jar、helloworld-1-0.0.1-SNAPSHOT-sources.jar這樣一些附屬構件,其包含了java文檔和源代碼。這時候,javadoc和sources就是這兩個附屬構件的classifier。這樣,附屬構件也就擁有了自己唯一的座標。
項目構件的文件名是與座標相對應, 規則爲: artifactId-version[-classifier].packaging,[-classifier]爲可選。
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.x</groupId> <artifactId>helloworld</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>helloworld Maven Webapp</name> <properties> <spring>3.0.5.RELEASE</spring> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring}</version> </dependency> </dependencies> </project>
dependencies節點可以包含一個或多個dependency元素,以聲明一個或多個項目依賴。
每個依賴可以包含的元素有:
groupId,artifactId和version:依賴的基本座標,對於任何一個依賴來說,基本座標是最重要的,maven根據座標才能找到需要的依賴。
type:依賴的類型,對於項目座標定義的packaging,默認值爲jar。
scope:依賴範圍。
optional:標記依賴是否可選。
exclusions:用來排除傳遞性依賴
*scope依賴範圍
maven在編譯項目主代碼的時候需要使用一套classpath。假如,在編譯項目主代碼的時候需要用到spring-core,該文件以依賴的方式被引入到classpath中。其次,maven在編譯和執行測試代碼的時候會使用另外一套classpath。如:JUnit就是一個很好的例子,該文件也以依賴的方式引入到測試使用的classpath中,不同的是這裏的依賴範圍是test。最後,實際運行maven項目的時候,又會使用一套classpath。
依賴範圍就是用來控制依賴與這三種classpath(編譯classpath,測試classpath,運行classpath)的關係,maven有以下幾種依賴範圍:
1.compile :編譯依賴範圍。如果沒有指定,就會默認使用該依賴範圍。使用此依賴範圍的maven依賴,對於編譯、測試、運行三種classpath都有效。典型的例子如項目依賴spring。
2.test :測試依賴範圍。使用此依賴範圍的maven依賴,只對於測試classpath有效,在編譯主代碼或者運行項目時將無法使用此類依賴。典型的例子是:JUnit,它只有在編譯測試代碼及運行測試的時候才需要。
3.provided : 已提供依賴範圍。使用此依賴範圍的maven依賴,對於編譯和測試classpath有效,但在運行時無效。典型的例子是:servlet-api,編譯和測試項目的時候需要該依賴,但在運行項目的時候,由於容器已經提供,就不需要maven重複地引入一遍。
4.runtime:運行時依賴範圍。使用此依賴範圍的maven依賴,對於測試和運行classpath有效,但在編譯主代碼時無效。典型的例子是JDBC驅動實現,項目主代碼的編譯只需要JDK提供的JDBC接口,只有在執行測試或者運行項目的時候才需要實現上述接口的具體JDBC驅動。
5.system: 系統依賴範圍。該依賴與三種classpath的關係,和provided依賴範圍完全一致。但是,使用system範圍的依賴時必須通過systemPath元素顯式地指定依賴文件的路徑。
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jar</systemPath> </dependency>
6.import:導入依賴範圍。在依賴dependencyManagement下使用,作用是將目標的pom中dependencyManagement導入合併到當前pom的dependencyManagement元素中。
小結:
maven引入的傳遞性依賴機制,一方面大大簡化和方便了依賴聲明,另一方面,大部分情況下我們只需要關心項目的直接依賴是什麼,而不用考慮這些直接依賴會引入什麼傳遞性依賴。但有時候,當傳遞性依賴造成問題的時候,我們就需要清楚地知道該傳遞性依賴是從哪條依賴路徑引入的。
例如,項目A有這樣的依賴關係 : A-->B-->C-->X(1.0)、A-->D-->X(2.0),X是A的傳遞性依賴,但是兩條依賴路徑上有兩個版 本的X,那麼哪個X會被maven解析使用呢?兩個版本都被解析顯然是不對的,因爲那會造成依賴重複,因此必須選擇一個。maven依賴調解的第一原則:路徑最近者優先。該例中X(1.0)的路徑長度爲3,而X(2.0)的路徑長度爲2,因此X(2.0)會被解析使用。
依賴調解第一原則不能解決所有問題,比如這樣的依賴關係:A-->B-->Y(1.0),A-->C-->Y(2.0),Y(1.0)和Y(2.0)的依賴路徑長度是一樣的,都爲2。那麼到底誰會被解析使用呢?在maven2.0.8及之前的版本中,這是不確定的,但是maven2.0.9開始,爲了儘可能避免構建的不確定性,maven定義了依賴調解的第二原則:第一聲明者優先。在依賴路徑長度相等的前提下,在POM中依賴聲明的順序決定了誰會被解析使用。順序最靠前的那個依賴優勝。
* Maven倉庫
在項目開發中, 項目目錄下往往會有一個lib目錄,用來存放第三方依賴jar文件, 如spring log4j jar等文件,
Maven倉庫就是放置JAR文件(WAR,ZIP,POM等等)的地方,所有Maven項目可以從同一個Maven倉庫中獲取自己所需要的依賴JAR,節省了磁盤資源,
也節省了時間 不用拷來拷去的。
此外,由於Maven倉庫中所有的JAR都有其自己的座標,該座標告訴Maven它的組ID,構件ID,版本,打包方式等等,因此Maven項目可以方便的進行依賴版本管理。
你也不在需要提交JAR文件到SCM倉庫中,你可以建立一個組織層次的Maven倉庫,供所有成員使用。
* 倉庫分類
在運行Maven的時,Maven所需要的依賴構件都是直接從本地倉庫獲取的,如果本地倉庫有依賴構建,直接使用;
如果本地倉庫沒有,它會首先嚐試從遠程倉庫下載構件至本地倉庫,然後再使用本地倉庫的構件。
* 本地倉庫缺省地址在${user.home}/.m2/repository目錄下,(例如:C:\Documents and Settings\Administrator\.m2\repository)
自定義本地倉庫位置:
配置進入maven/conf目錄 編輯settings.xml文件 修改localRepository節點
*中央倉庫 是一個默認的遠程倉庫, 安裝好Maven之後,我們可以建立一個簡單的項目,配置一些簡單的依賴,然後運行mvn clean install,項目就構建好了。我們沒有手工的去下載任何jar文件,這一切都是因爲Maven中央倉庫的存在,當Maven在本地倉庫找不到需要的jar文件時,它會查找遠程倉庫,而一個原始的Maven安裝就自帶了一個遠程倉庫——Maven中央倉庫。 這個Maven中央倉庫是在apache-maven3\lib\maven-model-builder-3.0.4.jar中定義,
超級POM: \org\apache\maven\project\pom-4.0.0.xml
*私服是一種特殊的遠程倉庫 爲了節省寬帶資源和時間 應該在局域網內架設一個私有的倉庫服務器,私服代理廣域網上的遠程倉庫, 供局域網內的Maven用戶使用,
當Maven需要下載構建的時候,先給私服倉庫發出請求, 如果私服上不存在構建,則從外部的遠程倉庫下載,緩存到私服倉庫中,再爲maven的下載請求提供服務。
* 遠程倉庫配置
1.編輯項目pom文件
<repositories> <repository> <id>maven-net-cn</id> <name>Maven China Mirror</name> <url>http://maven.net.cn/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>maven-net-cn</id> <name>Maven China Mirror</name> <url>http://maven.net.cn/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories>
repositories節點下,可以有多個repository,每個repository都有一個唯一的ID,一個name,以及最重要的,遠程倉庫的url。
此外<releases><enabled>true</enabled></releases>告訴Maven可以從這個倉庫下載releases版本的構件,而<snapshots><enabled>false</enabled></snapshots>告訴Maven不要從這個倉庫下載snapshot版本的構件。
2.在settings.xml中配置全局的遠程倉庫
在每個項目的pom中配置遠程倉庫 只是針對當前項目, 如果有10個項目 那就要配置10次 重複配置可以做到只配置一次,就是在settings.xml中做全局配置
<settings> ... <profiles> <profile> <id>dev</id> <!-- repositories and pluginRepositories here--> </profile> </profiles> <activeProfiles> <activeProfile>dev</activeProfile> </activeProfiles> ... </settings>
* 遠程倉庫認證
編輯conf/settings.xml文件
<servers> <server> <id>和pom文件中repository->id元素相同</id> <privateKey>/path/to/private/key</privateKey> <passphrase>optional; leave empty if not used.</passphrase> </server> </servers>
server元素的id必須和pom中需要認證的repository元素完全一直。
* 構建部署至遠程倉庫
mvn install 會將項目生成的構件安裝到本地Maven倉庫,mvn deploy 用來將項目生成的構件分發到遠程Maven倉庫。
本地Maven倉庫的構件只能供當前用戶使用,在分發到遠程Maven倉庫之後,所有能訪問該倉庫的用戶都能使用你的構件。
配置POM的distributionManagement來指定Maven的部署位置
<project> ... <distributionManagement> <repository> <id>nexus-releases</id> <name>Nexus Release Repository</name> <url>http://127.0.0.1:8088/nexus/content/repositories/releases/</url> </repository> <snapshotRepository> <id>nexus-snapshots</id> <name>Nexus Snapshot Repository</name> <url>http://127.0.0.1:8088/nexus/content/repositories/snapshots/</url> </snapshotRepository> </distributionManagement> ... </project>
Maven區別對待release版本的構件和snapshot版本的構件,snapshot爲開發過程中的版本,實時,但不穩定,release版本則比較穩定。
Maven會根據你項目的版本來判斷將構件分發到哪個倉庫。
一般來說,分發構件到遠程倉庫需要認證,如果你沒有配置任何認證信息,你往往會得到401錯誤。這個時候,如下在settings.xml中配置認證信息:
<settings> ... <servers> <server> <id>nexus-releases</id> <username>username</username> <password>password</password> </server> <server> <id>nexus-snapshots</id> <username>username</username> <password>password</password> </server> </servers> ... </settings>
* 鏡像
<settings> ... <mirrors> <mirror> <id>maven-net-cn</id> <name>Maven China Mirror</name> <url>http://maven.net.cn/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> ... </settings>
*聚合(多模塊)
在一個項目中 往往有多個模塊組成,例如有項目demo下面有a, b兩個模塊
爲了能使用一條命令就能構建demo-a, demo-b兩個模塊, 需要創建一個額外的聚合模塊, 然後通過該模塊構建整個項目的所有模塊。
聚合模塊(demo-parent) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <packaging>pom</packaging> <version>0.0.1-SNAPSHOT</version> <name>demo-parent Maven Webapp</name> <url>http://maven.apache.org</url> <modules> <module>../demo-a</module> <module>../demo-b</module> </modules> </project>
模塊a(demo-a) pom:
<project xmlns="<a href="http://maven.apache.org/POM/4.0.0">http://maven.apache.org/POM/4.0.0</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>" xsi:schemaLocation="<a href="http://maven.apache.org/POM/4.0.0">http://maven.apache.org/POM/4.0.0</a> <a href="http://maven.apache.org/maven-v4_0_0.xsd">http://maven.apache.org/maven-v4_0_0.xsd</a>"> <modelVersion>4.0.0</modelVersion> <groupId>com.x.demo</groupId> <artifactId>demo-a</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>demo-a Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>demo-a</finalName> </build> </project>
模塊b(demo-b) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.x.demo</groupId> <artifactId>demo-b</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>demo-b Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>demo-b</finalName> </build> </project>
額外模塊(demo-parent) pom中的modules節點有多個module,每個module的值都是一個被聚合模塊的相對目錄。
關於聚合模塊目錄與其他模塊的目錄主要有兩種形式:
a.父子關係:
父子關係 聚合模塊的pom:
<modules> <module>demo-a</module> <module>demo-b</module> </modules>
a.平行目錄:
平行目錄 聚合模塊的pom:
<modules> <module>../demo-a</module> <module>../demo-b</module> </modules>
最後在聚合模塊(demo-parent)的pom上面 運行mvn命令 根據聚合順序依次構建多個模塊。
*繼承
上面的例子中, a,b兩個模塊都依賴junit, 爲了消除重複,可以使用pom的繼承,以達到一處聲明,多處使用的目的。
聚合模塊(demo-parent) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <packaging>pom</packaging> <version>0.0.1-SNAPSHOT</version> <name>demo-parent Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <modules> <module>../demo-a</module> <module>../demo-b</module> </modules> </project>
模塊a(demo-a) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../demo-parent/pom.xml</relativePath> </parent> <artifactId>demo-a</artifactId> <name>demo-a Maven Webapp</name> <build> <finalName>demo-a</finalName> </build> </project>
模塊b(demo-b) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../demo-parent/pom.xml</relativePath> </parent> <artifactId>demo-b</artifactId> <name>demo-a Maven Webapp</name> <build> <finalName>demo-b</finalName> </build> </project>
parent元素聲明父模塊,parent下的子節點groupId,artifactId,version指定父模塊的座標,這三個元素是必須的。
節點relativePath指定父模塊pom的路徑,默認值是:../pom.xml,也就是說父pom在上一層目錄,(<relativePath>../demo-parent/pom.xml</relativePath> 表示父模塊pom和子模塊是平行目錄)
可以被繼承的POM元素:
groupId:項目id,項目座標的核心元素
version:項目版本,項目座標的核心元素
description:項目描述信息
organization:項目組織信息
inceptionYear:項目創世年月
developers:項目開發者信息
contributors:項目貢獻者信息
distributionManagement:項目部署配置
scm:項目的版本控制信息
mailingLists:項目郵件列表信息
properties:自定義的屬性
dependencies:項目的依賴配置
dependencyManagement:項目的依賴管理配置
repositories:項目的倉庫配置
build:項目源碼目錄配置。輸出目錄配置,插件配置等。
*依賴管理
父模塊(demo-parent) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <packaging>pom</packaging> <version>0.0.1-SNAPSHOT</version> <name>demo-parent Maven Webapp</name> <url>http://maven.apache.org</url> <!-- dependencyManagement 定義的依賴 需要在子pom中聲明 不然不會產生效果 --> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement> <modules> <module>../demo-a</module> <module>../demo-b</module> </modules> </project>
模塊a(demo-a) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../demo-parent/pom.xml</relativePath> </parent> <artifactId>demo-a</artifactId> <name>demo-a Maven Webapp</name> <properties> <mail.version>1.4.1</mail.version> </properties> <dependencies> <!-- 聲明父pom中的依賴 這樣纔會真正被使用 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <!-- 擴展依賴 父pom中並沒有聲明 不會影響到父POM 和其他模塊 --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>${mail.version}</version> </dependency> </dependencies> <build> <finalName>demo-a</finalName> </build> </project>
模塊b(demo-b) pom:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.x.demo</groupId> <artifactId>demo-parent</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../demo-parent/pom.xml</relativePath> </parent> <artifactId>demo-b</artifactId> <name>demo-a Maven Webapp</name> <!-- 沒有聲明父pom中的依賴 不會被使用 --> <build> <finalName>demo-b</finalName> </build> </project>
父POM 中使用dependencyManagement 聲明的依賴不會給子模塊引入依賴, 只會繼承這段配置。
在模塊a(demo-a) pom中聲明瞭父pom中junit依賴 在執行的時候纔會獲得真正的依賴信息。
模塊b(demo-b) pom中沒有聲明父pom中junit依賴 不會產生實際效果
我們都知道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 進行撤銷。
舉例:
1、使用tomcat-maven-plugin插件自動化遠程發佈到Tomcat服務器
<!-- 配置自動發佈Tomcat插件(tomcat:redeploy) --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <configuration> <url>http://localhost:8080/manager/html</url> <username>zhoulumin</username> <password>19880627</password> <path>/sshe</path> </configuration> </plugin>
2、使用cargo-maven2-plugin插件配置Tomcat本地自動發佈(cargo:deploy)
<!-- 通過cargo-maven2-plugin插件配置Tomcat自動發佈(cargo:deploy) --> <plugin> <!-- 指定插件名稱及版本號 --> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.4.9</version> <!-- 插件的Tomcat6.x配置 --> <configuration> <wait>true</wait> <!--是否說明,操作start、stop等後續操作必須等前面操作完成才能繼續 --> <container> <!-- 容器的配置 --> <containerId>tomcat6x</containerId> <!-- 指定tomcat版本 --> <type>installed</type> <!-- 指定類型:standalone, installed等 --> <home>E:/zhoulumin/tools/fbrp-ide-32bit/apache-tomcat-6.0.35</home> <!-- 指定Tomcat的位置,即catalina.home --> </container> <configuration> <!-- 具體的配置 --> <type>existing</type> <!-- 類型,existing:存在 --> <home>E:/zhoulumin/tools/fbrp-ide-32bit/apache-tomcat-6.0.35</home> <!-- Tomcat的位置,即catalina.home --> </configuration> <deployables> <!-- 部署設置 --> <deployable> <!-- 部署的war包名等 --> <groupId>com.chowmin.sshe</groupId> <artifactId>sshe</artifactId> <type>war</type> <properties> <context>sshe</context> <!-- 部署路徑 --> </properties> </deployable> </deployables> </configuration> <executions> <!-- 執行的動作 --> <execution> <id>verify-deployer</id> <phase>install</phase> <!-- 解析install --> <goals> <goal>deployer-deploy</goal> </goals> </execution> <execution> <id>clean-deployer</id> <phase>clean</phase> <goals> <goal>deployer-undeploy</goal> </goals> </execution> </executions> </plugin>
3、使用cargo-maven2-plugin插件配置Tomcat遠程自動發佈(cargo:deploy)
<!-- 通過cargo-maven2-plugin插件配置Tomcat自動發佈(cargo:deploy) --> <plugin> <!-- 指定插件名稱及版本號 --> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.4.9</version> <!-- 插件的Tomcat6.x配置 --> <configuration> <wait>true</wait> <!--是否說明,操作start、stop等後續操作必須等前面操作完成才能繼續 --> <container> <!-- 容器的配置 --> <containerId>tomcat6x</containerId> <!-- 指定tomcat版本 --> <type>remote</type> <!-- 指定類型:standalone, installed等 --> </container> <configuration> <!-- 具體的配置 --> <type>runtime</type> <!-- 類型,existing:存在 --> <properties> <!-- 配置屬性 --> <cargo.tomcat.manager.url>http://localhost:8080/manager</cargo.tomcat.manager.url> <!-- 管理地址 --> <cargo.remote.username>zhoulumin</cargo.remote.username> <!-- Tomcat用戶名 --> <cargo.remote.password>19880627</cargo.remote.password> <!-- Tomcat密碼 --> <cargo.tomcat.ajp.port>8009</cargo.tomcat.ajp.port> <!-- Ajp端口 --> </properties> </configuration> <deployables> <!-- 部署設置 --> <deployable> <!-- 部署的war包名等 --> <groupId>com.chowmin.sshe</groupId> <artifactId>sshe</artifactId> <type>war</type> <properties> <context>sshe</context> <!-- 部署路徑 --> </properties> </deployable> </deployables> </configuration> <executions> <!-- 執行的動作 --> <execution> <id>verify-deployer</id> <phase>install</phase> <!-- 解析install --> <goals> <goal>deployer-deploy</goal> </goals> </execution> <execution> <id>clean-deployer</id> <phase>clean</phase> <goals> <goal>deployer-undeploy</goal> </goals> </execution> </executions> </plugin>
“打包“這個詞聽起來比較土,比較正式的說法應該是”構建項目軟件包“,具體說就是將項目中的各種文件,比如源代碼、編譯生成的字節碼、配置文件、文檔,按照規範的格式生成歸檔,最常見的當然就是JAR包和WAR包了,複雜點的例子是Maven官方下載頁面的分發包,它有自定義的格式,方便用戶直接解壓後就在命令行使用。作爲一款”打包工具“,Maven自然有義務幫助用戶創建各種各樣的包,規範的JAR包和WAR包自然不再話下,略微複雜的自定義打包格式也必須支持,本文就介紹一些常用的打包案例以及相關的實現方式,除了前面提到的一些包以外,你還能看到如何生成源碼包、Javadoc包、以及從命令行可直接運行的CLI包。
Packaging的含義
任何一個Maven項目都需要定義POM元素packaging(如果不寫則默認值爲jar)。顧名思義,該元素決定了項目的打包方式。實際的情形中,如果你不聲明該元素,Maven會幫你生成一個JAR包;如果你定義該元素的值爲war,那你會得到一個WAR包;如果定義其值爲POM(比如是一個父模塊),那什麼包都不會生成。除此之外,Maven默認還支持一些其他的流行打包格式,例如ejb3和ear。你不需要了解具體的打包細節,你所需要做的就是告訴Maven,”我是個什麼類型的項目“,這就是約定優於配置的力量。
爲了更好的理解Maven的默認打包方式,我們不妨來看看簡單的聲明背後發生了什麼,對一個jar項目執行mvn package操作,會看到如下的輸出:
[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ git-demo --- [INFO] Building jar: /home/juven/git_juven/git-demo/target/git-demo-1.2-SNAPSHOT.jar
相比之下,對一個war項目執行mvn package操作,輸出是這樣的:
[INFO] --- maven-war-plugin:2.1:war (default-war) @ webapp-demo --- [INFO] Packaging webapp [INFO] Assembling webapp [webapp-demo] in [/home/juven/git_juven/webapp-demo/target/webapp-demo-1.0-SNAPSHOT] [INFO] Processing war project [INFO] Copying webapp resources [/home/juven/git_juven/webapp-demo/src/main/webapp] [INFO] Webapp assembled in [90 msecs] [INFO] 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>
源碼包和Javadoc包
一個Maven項目只生成一個主構件,當需要生成其他附屬構件的時候,就需要用上classifier。源碼包和Javadoc包就是附屬構件的極佳例子。它們有着廣泛的用途,尤其是源碼包,當你使用一個第三方依賴的時候,有時候會希望在IDE中直接進入該依賴的源碼查看其實現的細節,如果該依賴將源碼包發佈到了Maven倉庫,那麼像Eclipse就能通過m2eclipse插件解析下載源碼包並關聯到你的項目中,十分方便。由於生成源碼包是極其常見的需求,因此Maven官方提供了一個插件來幫助用戶完成這個任務:
<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>
類似的,生成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用戶更方便的使用Maven中央庫中海量的資源,中央倉庫的維護者強制要求開源項目提交構件的時候同時提供源碼包和Javadoc包。這是個很好的實踐,讀者也可以嘗試在自己所處的公司內部實行,以促進不同項目之間的交流。
可執行CLI包
除了前面提到了常規JAR包、WAR包,源碼包和Javadoc包,另一種常被用到的包是在命令行可直接運行的CLI(Command Line)包。默認Maven生成的JAR包只包含了編譯生成的.class文件和項目資源文件,而要得到一個可以直接在命令行通過java命令運行的JAR文件,還要滿足兩個條件:
- JAR包中的/META-INF/MANIFEST.MF元數據文件必須包含Main-Class信息。
- 項目所有的依賴都必須在Classpath中。
Maven有好幾個插件能幫助用戶完成上述任務,不過用起來最方便的還是maven-shade-plugin,它可以讓用戶配置Main-Class的值,然後在打包的時候將值填入/META-INF/MANIFEST.MF文件。關於項目的依賴,它很聰明地將依賴JAR文件全部解壓後,再將得到的.class文件連同當前項目的.class文件一起合併到最終的CLI包中,這樣,在執行CLI JAR文件的時候,所有需要的類就都在Classpath中了。下面是一個配置樣例:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.juvenxu.mavenbook.HelloWorldCli</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
上述例子中的,我的Main-Class是com.juvenxu.mavenbook.HelloWorldCli,構建完成後,對應於一個常規的hello-world-1.0.jar文件,我還得到了一個hello-world-1.0-cli.jar文件。細心的讀者可能已經注意到了,這裏用的是cli這個classifier。最後,我可以通過java -jar hello-world-1.0-cli.jar命令運行程序。
自定義格式包
實際的軟件項目常常會有更復雜的打包需求,例如我們可能需要爲客戶提供一份產品的分發包,這個包不僅僅包含項目的字節碼文件,還得包含依賴以及相關腳本文件以方便客戶解壓後就能運行,此外分發包還得包含一些必要的文檔。這時項目的源碼目錄結構大致是這樣的:
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> </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)
- 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的分發包了。
小結
打包是項目構建最重要的組成部分之一,本文介紹了主流Maven打包技巧,包括默認打包方式的原理、如何製作源碼包和Javadoc包、如何製作命令行可運行的CLI包、以及進一步的,如何基於個性化需求自定義打包格式。這其中涉及了很多的Maven插件,當然最重要,也是最爲複雜和強大的打包插件就是maven-assembly-plugin。事實上Maven本身的分發包就是通過maven-assembly-plugin製作的,感興趣的讀者可以直接查看源碼一窺究竟。