换个视角看 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。