讀古今文學網 > Maven實戰 > 8.5 約定優於配置 >

8.5 約定優於配置

標準的重要性已不用過多強調,想像一下,如果不是所有程序員都基於HTTP協議開發Web應用,互聯網會亂成怎樣。各個版本的IE、Firefox等瀏覽器之間的差別已經讓很多開發者頭痛不已。而Java成功的重要原因之一就是它能屏蔽大部分操作系統的差異,XML流行的原因之一是所有語言都接受它。Maven當然還不能和這些既成功又成熟的技術相比,但Maven的用戶都應該清楚,Maven提倡「約定優於配置」(Convention Over Configuration),這是Maven最核心的設計理念之一。

那麼為什麼要使用約定而不是自己更靈活的配置呢?原因之一是,使用約定可以大量減少配置。先看一個簡單的Ant配置文件,見代碼清單8-23。

代碼清單8-23 構建簡單項目使用的Ant配置文件

這段代碼做的事情就是清除構建目錄、創建目錄、編譯代碼、複製依賴至目標目錄,最後打包。這是一個項目構建要完成的最基本的事情,不過為此還是需要寫很多的XML配置:源碼目錄是什麼、編譯目標目錄是什麼、分發目錄是什麼,等等。用戶還需要記住各種Ant任務命令,如delete、mkdir、javac和jar。

做同樣的事情,Maven需要什麼配置呢?Maven只需要一個最簡單的POM,見代碼清單8-24。

代碼清單8-24 構建簡單項目使用的Maven配置文件

這段配置簡單得令人驚奇,但為了獲得這樣簡潔的配置,用戶是需要付出一定的代價的,那就是遵循Maven的約定。Maven會假設用戶的項目是這樣的:

·源碼目錄為src/main/java/

·編譯輸出目錄為target/classes/

·打包方式為jar

·包輸出目錄為target/

遵循約定雖然損失了一定的靈活性,用戶不能隨意安排目錄結構,但是卻能減少配置。更重要的是,遵循約定能夠幫助用戶遵守構建標準。

如果沒有約定,10個項目可能使用10種不同的項目目錄結構,這意味著交流學習成本的增加,當新成員加入項目的時候,它就不得不花時間去學習這種構建配置。而有了Maven的約定,大家都知道什麼目錄放什麼內容。此外,與Ant的自定義目標名稱不同,Maven在命令行暴露的用戶接口是統一的,像mvn clean install這樣的命令可以用來構建幾乎任何的Maven項目。

也許這時候有讀者會問,如果我不想遵守約定該怎麼辦?這時,請首先問自己三遍,你真的需要這麼做嗎?如果僅僅是因為喜好,就不要耍個性,個性往往意味著犧牲通用性,意味著增加無謂的複雜度。例如,Maven允許你自定義源碼目錄,如代碼清單8-25所示。

代碼清單8-25 使用Maven自定義源碼目錄

該例中源碼目錄就成了src/java而不是默認的src/main/java。但這往往會造成交流問題,習慣Maven的人會奇怪,源代碼去哪裡了?當這種自定義大量存在的時候,交流成本就會大大提高。只有在一些特殊的情況下,這種自定義配置的方式才應該被正確使用以解決實際問題。例如你在處理遺留代碼,並且沒有辦法更改原來的目錄結構,這個時候就只能讓Maven妥協。

本書曾多次提到超級POM,任何一個Maven項目都隱式地繼承自該POM,這有點類似於任何一個Java類都隱式地繼承於Object類。因此,大量超級POM的配置都會被所有Maven項目繼承,這些配置也就成為了Maven所提倡的約定。

對於Maven 3,超級POM在文件$MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路徑下。對於Maven 2,超級POM在文件$MAVEN_HOME/lib/maven-x.x.x-uber.jar中的org/apache/maven/project/pom-4.0.0.xml目錄下。這裡的x.x.x表示Maven的具體版本。

超級POM的內容在Maven 2和Maven 3中基本一致,現在分段看一下,見代碼清單8-26。

代碼清單8-26 超級POM中關於倉庫的定義

首先超級POM定義了倉庫及插件倉庫,兩者的地址都為中央倉庫http://repo1.maven.org/maven2,並且都關閉了SNAPSHOT的支持。這也就解釋了為什麼Maven默認就可以按需要從中央倉庫下載構件。

再看以下內容,見代碼清單8-27。

代碼清單8-27 超級POM中關於項目結構的定義

這裡依次定義了項目的主輸出目錄、主代碼輸出目錄、最終構件的名稱格式、測試代碼輸出目錄、主源碼目錄、腳本源碼目錄、測試源碼目錄、主資源目錄和測試資源目錄。這就是Maven項目結構的約定。

緊接著超級POM為核心插件設定版本,見代碼清單8-28。

代碼清單8-28 超級POM中關於插件版本的定義

由於篇幅原因,這裡不完整羅列,讀者可自己找到超級POM瞭解插件的具體版本。Maven設定核心插件的原因是防止由於插件版本的變化而造成構建不穩定。

超級POM的最後是關於項目報告輸出目錄的配置和一個關於項目發佈的profile,這裡暫不深入解釋。後面會有相關的章節討論這兩項配置。

可以看到,超級POM實際上很簡單,但從這個POM我們就能夠知曉Maven約定的由來,不僅理解了什麼是約定,為什麼要遵循約定,還能明白約定是如何實現的。