換個視角看 Maven:一個領域平臺的優美設計
作為一個Java程序員,Maven是再熟悉不過的工具了, 它提供了構建項目的一個框架, 在默認情況下為我們提供了許多常用的Plugin,其中便包括構建Java項目的Plugin,還有War,Ear等。除此之外還提供內建的項目生命周期管理。
以上是我們最熟悉的maven的一面。 下面我們要從領域平臺設計的角度,分析Maven的優美設計,為我們做領域平臺化提供參考,最后我們再來思考如何做招商的領域平臺。
Maven是領域驅動設計實現的,作為一個強大的項目管理構建平臺而實現
我們先會介紹maven的基本模型,概念以及功能。 然后我們在分析這個領域平臺在領域設計上的一些亮點。最后我們再延伸思考,如果用maven的思路我們可以在阿里的業務系統平臺化中得到什么啟示。
Maven的用途,核心概念,用法,擴展等
Maven的基本介紹
Maven 是 Apache 組織下的一個通用項目管理工具,它主要用來幫助實現項目的構建、測試、打包和部署。Maven 提供了標準的軟件生命周期模型和構建模型,通過配置就能對項目進行全面的管理。它Maven 將構建的過程抽象成一個個的生命周期過程,在不同的階段使用不同的已實現插件來完成相應的實際工作,這種設計方法極大的避免了設計和腳本編碼的重復,極大 的實現了復用。
Maven的核心概念
-
POM
這是Maven最重要的一個概念, pom是指project object Model。pom是一個xml,在maven2里為pom.xml。是maven工作的基礎,在執行task或者goal時,maven會去項目根目錄下讀取pom.xml獲得需要的配置信息
這個POM,就是maven平臺的領域對象。 Maven就是圍繞這個POM領域對象構建起來的領域平臺。
pom文件中包含了項目的信息和maven build項目所需的配置信息,通常有項目信息(如版本、成員)、項目的依賴、插件和goal、build選項等等
pom是可以繼承的,通常對于一個大型的項目或是多個module的情況,子模塊的pom需要指定父模塊的pom
pom文件中節點含義如下:
project
pom文件的頂級元素
modelVersion
所使用的object model版本,為了確保穩定的使用,這個元素是強制性的。 除非maven開發者升級模板,否則不需要修改
groupId
是項目創建團體或組織的唯一標志符,通常是域名倒寫, 如groupId org.apache.maven.plugins就是為所有maven插件預留的
artifactId
是項目artifact唯一的基地址名
packaging
artifact打包的方式,如jar、war、ear等等。默認為jar。 這個不僅表示項目最終產生何種后綴的文件,也表示build過程使用什么樣的lifecycle。
version
artifact的版本,通常能看見為類似0.0.1-SNAPSHOT,其中SNAPSHOT表示項目開發中,為開發版本
name
表示項目的展現名,在maven生成的文檔中使用
url
表示項目的地址,在maven生成的文檔中使用
description
表示項目的描述,在maven生成的文檔中使用
dependencies
表示依賴,在子節點dependencies中添加具體依賴的groupId artifactId和version
build
表示build配置
parent
表示父pom
groupId:artifactId:version唯一確定了一個artifact
-
Artifact
一個項目將要產生的文件,可以是jar文件,源文件,二進制文件,war文件,甚至是pom文件。每個artifact都由groupId:artifactId:version組成的標識符唯一識別。需要被使用(依賴)的artifact都要放在倉庫
-
Repositories
Repositories是用來存儲Artifact的。如果說我們的項目產生的 Artifact是一個個小工具,那么Repositories就是一個倉庫,里面有我們自己創建的工具,也可以儲存別人造的工具,我們在項目中需要使用 某種工具時,在pom中聲明dependency,編譯代碼時就會根據dependency去下載工具(Artifact),供自己使用。
對于自己的項目完成后可以通過mvn install命令將項目放到倉庫(Repositories)中
倉庫分為本地倉庫和遠程倉庫,遠程倉庫是指遠程服務器上用于存儲Artifact的倉庫,本地倉庫是指本機存儲Artifact的倉庫,對于windows機器本地倉庫地址為系統用戶的.m2/repository下面。對于需要的依賴,在pom中添加dependency即可,可以在maven的倉庫中搜索:http://mvnrepository.com/
-
Build(Lifecycle -> Phase -> Goal)
Lifecycle(生 命周期),是指一個項目build的過程。這是maven最高級別的的控制單元,它是一系列的phase組成,也就是說,一個生命周期,就是一個大任務的 總稱,不管它里面分成多少個子任務,反正就是運行一個lifecycle,就是交待了一個任務,運行完后,就得到了一個結果,中間的過程,是phase完 成的,自己可以定義自己的lifecycle,包含自己想要的phase
maven的Build Lifecycle分為三種,分別為default(處理項目的部署)、clean(處理項目的清理)、site(處理項目的文檔生成)。他們都包含不同的lifecycle。
可以理解為任務單元,lifecycle是總任務,phase就是總任務分出來的一個個子任務,但是這些子任務是被規格化的,它可以同時被多個lifecycle所包含, 一個lifecycle可以包含任意個phase,phase的執行是按順序的,一個phase可以綁定很多個goal,至少為一個,沒有goal的 phase是沒有意義的
下面重點介紹default Build Lifecycle幾個重要的phase:
validate
驗證項目是否正確以及必須的信息是否可用
compile
編譯源代碼
test
測試編譯后的代碼,即執行單元測試代碼
package
打包編譯后的代碼,在target目錄下生成package文件
integration-test
處理package以便需要時可以部署到集成測試環境
verify
檢驗package是否有效并且達到質量標準
install
安裝package到本地倉庫,方便本地其它項目使用
deploy
部署,拷貝最終的package到遠程倉庫和替他開發這或項目共享,在集成或發布環境完成
以上的phase是有序的(注意實際兩個相鄰phase之間還有其他phase被省略,完整phase見lifecycle),下面一個phase的執行必須在上一個phase完成后
若直接以某一個phase為goal,將先執行完它之前的phase,如mvn install
將會先validate -> compile -> test -> package -> integration-test ->verify最后再執行install phasegoal代表一個特定任務
A goal represents a specific task (finer than a build phase) which contributes to the building and managing of a project.
mvn package表示打包的任務,通過上面的介紹我們知道,這個任務的執行會先執行package phase之前的phase
mvn deploy表示部署的任務
mven clean install則表示先執行clean的phase(包含其他子phase),再執行install的phase。
mojo:
lifecycle與phase與goal都是概念上的東西,mojo才是做具體事情的, 可以簡單理解mojo為goal的實現類,它繼承于AbstractMojo, 有一個execute方法,goal等的定義都是通過在mojo里定義一些 注釋的anotation來實現的,maven會在打包時,自動根據這些anotation 生成一些xml文件,放在plugin的jar包里
-
Archetype
原型對于項目的作用就相當于模具對于工具的作用,我們想做一個錘子,將鐵水倒入模具成型后,稍加修改就可以了。
類似我們可以根據項目類型的需要使用不同的Archetype創建項目。通過Archetype我們可以快速標準的創建項目。利用Archetype創建完項目后都有標準的文件夾目錄結構
既然Archetype相當于模具,那么當然可以自己再造模具了啊,創建Archetype
下面介紹利用maven自帶的集中Archetype創建項目。創建項目的goal為 mvn archetype:generate,并且指定archetypeArtifactId,其中archetypeArtifactId見maven自帶 的archetypeArtifactId
-
Plugin
maven的核心僅僅定義了抽象的生命周期,具體的任務是交由插件完成的,插件以獨立的形式存在。
對于插件本身,為了能夠復用代碼,它往往能夠完成多個任務。如maven-dependency-plugin有十多個目標,每個目標對應了一個功能,如 dependency:analyze、 dependency:tree和dependency:list。這是一種通用的寫法,冒號前面是插件前綴,后面是該插件的目標。maven的生命周期與插件相互綁定,用以完成實際的構建任務。具體而言,是生命周期的 階段與插件的目標相互綁定,已完成某個具體的構建任務。例如項目編譯這一任務,它對應了default生命周期的compile階段,而maven- compiler-plugin這一插件的compile目標能夠完成該任務,因此將他們綁定。
比如maven缺省的三個生命周期: clean, default, site和插件綁定如下:
Clean
clean clean:clean
Site
site site:site site-deploy site:deploy
Default
process-resources resources:resources compile compiler:compile process-test-resources resources:testResources test-compile compiler:testCompile test surefire:test package ejb:ejb or ejb3:ejb3 or jar:jar or par:par or rar:rar or war:war install install:install deploy deploy:deploy
用戶還能夠自己選擇獎某個插件目標綁定到生命周期的某個階段以執行更多更特色的任務。
比如:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.1</version> <executions> <execution> <id>copy</id> <phase>install</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>lib</outputDirectory> </configuration> </execution> </executions> </plugin>
定義了一個id為copy的任務,利用插件maven-dependency-plugin的copy-dependencies目標綁定到default生命周期的install階段,來實現項目依賴的jar包的自動復制。
當插件目標被綁定到不同的生命周期階段時候,其執行順序會有生命周期階段的先后順序決定的。如果多個目標被綁定到同一個階段,他們的執行順序是由插件聲明的先后順序決定目標的執行順序。
-
profile
一個優秀的構建系統必須足夠靈活,應該能夠讓項目在不同的環境下都能成功構建。maven為了支持構建的靈活性,內置了三大特性,即:屬性、profile和資源過濾。
profile定義了一系列的profile變量,在具體構建時可用使用其中的某個profile去變量替換資源文件。
Maven設計特點
在上面的介紹里我們花了很長的篇幅來介紹maven的模型,概念,功能,和運作方式。大家也跟了解Maven是基于project這個領域對象模型上,以項目周期管理為目標而構建的領域平臺。
-
設計了領域模型,所有的功能圍繞項目Project這個領域模型構建
-
設計了領域模型的生命周期和執行方式(lifecycle-phase-goal)
-
設計了項目的原型模式(architype)
-
設計了可擴展的插件體系(plugin-mojo)
-
設計了依賴管理(dependencies)
-
設計了動態配置機制(profile)
-
設計了artiface倉庫模型(repositories)
從這7個設計點可以看出,maven這個平臺設計得很清晰,對需要解決的問題(項目管理構建)設計了一系列的概念, 功能,流程,方便maven的使用者明確的掌握,同時又可以針對自己的個性化需要去定制擴展平臺的功能。
構建maven式領域平臺
前面我們都是在介紹Maven本身和他的設計特點。 現在我們要發散思考,這種設計在我們用來做自己業務系統的領域平臺時有什么可以借鑒。
Maven是基于領域模型驅動設計的平臺,圍繞這個業務模型,從他的起始狀態到結束狀態有一個明顯的生命周期概念, 在這個生命周期里,不同的功能點獨立實現同時又被復用形成多個順序執行的任務單元推動周期的執行。
在我們的業務系統中也有很多類似的需要。 比如下面我們用招商和交易下單為例。
招商平臺和Maven平臺類比
-
什么是招商
每年大促前期最重要的準備工作就是招商,招商就是淘寶小二創建了一個活動項目,設計這個 活動的玩法, 然后吸引一些商家帶著他們商品參加這個活動,然后小二通過各種資質驗證保證報名商家的資質,并通過各種條件在這些商家中選擇出最后參加活動的結果。然后這 個項目活動在參與者,玩法等確定下,去執行一些必要的動作,保障這個活動項目在活動期間能夠按照設計的完成。
-
招商的領域模型(domain)
招商中最重要的領域模型是活動,我們也可以更規范的成為活動項目(project),每一次小二開始一個招商活動,其實就是設計一個招商活動項目。項目里需要明確項目的參與者,項目的時間(報名期,審核期,活動期),項目的玩法,項目的產出和需要執行的任務。
-
活動項目的生命周期(lifecycle)
很直觀,我們就可以確定活動項目是有一個生命周期的。從小二創建活動項目開始到活動結束,基本會經歷一下周期,創建->報名->審核->啟動->運行->結束->收尾。
每個周期可以分多個階段,每個階段都有多個目標需要被執行。這些任務可以被靈活復用。
如何設計這些周期,階段和目標對招商平臺化是否成功有決定性作用。 -
活動項目的原型模板(architype)
每次小二設計一個活動項目,從資質,玩法,到運作方式等都需要做很多配置,管理。資深運 營小二如何把他們的經驗沉淀起來。避免下次類似的活動項目必須從頭開始,新手小二也很難設計出一個成功的活動。這些就需要把這些活動按照一定的模式沉淀成 原型(項目的模板),方便下一次即使是新手也可以快速的構建高效的活動項目。那么招商平臺就也需要設計類似maven 原型類似的功能。
-
可擴展的插件體系(plugin-mojo)
招商可以說是根據業務方需求,不停的響應提供新的功能支持新的需求等。當新的需求來的時 候,我們需要分析出平臺不足或者需要定制的功能點,然后以插件擴展的方式完成開發,同時能把這些功能很好的注冊沉淀到平臺,平臺的功.能隨著業務的發展越 來越強大。比如支持更多的資質校驗,支持更多的算法模型,對已有流程如何進行定制擴展,加入新的流程點等等。都需要平臺提供一個類maven的可擴展的插 件體系。
-
依賴管理(dependencies)
招商活動會有很多的依賴,比如IC,UIC,報名的商家和商品資源,搜索算法等等。如何把這些依賴類似maven一樣管理起來,對招商活動項目的運作和監控也就更加直觀。
-
動態配置機制(profile)
很明顯,這個機制對招商活動項目也很有用處,比如每次活動對商品的打標,活動時間之類都需要類似的功能機制去保障。方便小二的使用調整。比如小二可以預先準備一些配置,然后根據實際情況,切換不同的配置。
-
artiface倉庫模型(repositories)
活動項目依賴的各種插件實現, 活動結束后生成的案例資源,都可以以案例庫的方式存儲起來。方便更進一步的知識積累和業務擴展。
這些只是對招商這個復雜系統的初步想法,具體招商如何設計模型,生命周期等都需要結合目前招商的功能,按照這種思路,我相信我們的招商平臺會有一個很好的架構,以后也許我們可以給小二提供類似maven命令的方式來構建活動了,:)
mvn create 創建活動 mvn enroll 報名 mvn review 審核 mvn start 啟動 mvn close 結束 mvn clear 掃尾
招商平臺化會包括以下功能:
-
活動項目對象模型
-
活動項目構建引擎
-
開放平臺
-
原型管理
-
業務識別
-
...
通過這些我們打造一個強大的招商平臺。
交易下單平臺(Buy)和Maven平臺類比
另一個很類似的就是buy下單了,基于訂單模型,下單是個典型的生命周期,也很適合用maven的思路來設計。 大家也可以按照類似的思路分析下。 此處省略 1000字,:)。
mvn buy mvn promotion mvn ... mvn order
總結
在工具軟件里,有很多很好的設計,這些設計對我們做業務系統是個很好的參考。 比如Eclipse, Maven(還可以關注Gradle,這個設計更好),我們可以用這些平臺系統來作為我們平臺化的參考類比設計,開拓我們的思路。
文章來自阿里巴巴技術協會(ATA)精選集,原文首發于阿里云棲社區:http://yq.aliyun.com/articles/2916 。云棲社區是由阿里云負責運營、阿里巴巴技術協會和阿里巴巴集團各技術團隊提供內容支持的開放式技術社區:http://yq.aliyun.com。