Maven原型系统
原型(Archetype)是Maven的模板工具箱。利用原型,可以很容易的应用组织在软件实现方面的最佳实践,减轻搭建项目框架的负担。
原型机制支持“增量“方式,也就是说,你通过原型生成一个项目后,可以再次用另外一个原型来生成额外的内容到此项目中。这种增量机制允许将项目的不同方面/部分封装到多个原型中,增强可复用、可组合性。
从Maven原型创建项目,需要使用maven-archetype-plugin插件。
一般情况下Maven原型都存放在远程仓库中,Maven中心仓库默认可用,你也可以修改Maven的settings.xml添加别的原型仓库:
1 2 3 4 5 6 7 8 9 10 11 |
<repository> <id>archetype</id> <url>https://m2.gmem.cc/path/to/repo/</url> </repository> <!-- 如果需要身份验证 --> <server> <id>archetype</id> <username>user.name</username> <password>s3cr3t</password> </server> |
交互式调用archetype:generate时,maven-archetype-plugin会提示你从某个仓库选择原型,输入对应的序号即可。
使用filter可以减少原型列表的长度:
1 |
mvn archetype:generate -Dfilter=org.apache:struts |
选择原型后,maven-archetype-plugin会提示你输入一系列属性的值,最终生成新项目。
生成项目时,你需要提供新项目的GAV、package,原型还可能规定了一系列其它必须属性,这些属性会用来:
- 填充Velocity模板中的变量
- 如果目录、文件名包含 __property__,则被替换为对应的属性值
- __artifactId__被替换为项目的ArtifactId
- 在多模块项目中, __rootArtifactId__被替换为根项目的ArtifactId
你可以从零开始,开发一个原型,也可以从现有的项目反向生成原型。
原型描述符用于存储原型的元数据,它存放在原型JAR的 META-INF/maven/archetype-metadata.xml中。下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<archetype-descriptor xmlns="https://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.1.0 http://maven.apache.org/xsd/archetype-descriptor-1.1.0.xsd" <!-- 原型的名称--> <!-- 是否偏原型 --> name=.. partial=.. > <!-- 用户必须提供的属性列表 --> <requiredProperties> <requiredProperty key=.. > <defaultValue/> <validationRegex/> </requiredProperty> </requiredProperties> <!-- 文件集定义 --> <fileSets> <!-- 文件集说明了在生成项目的过程中,如何使用原型JAR中的文件 --> <!-- filtered 此文件集是否可以被过滤,如果true,则意味着这些文件被用作Velocity模板。否则原样拷贝 --> <!-- packaged 此文件集是否应该被生成/拷贝到package属性所指定的目录层次中 --> <!-- encoding 文件的编码方式 --> <fileSet filtered=.. packaged=.. encoding=.. > <directory/> <!-- 此文件集位于的目录 --> <includes><include></include></includes> <!-- 包含的文件列表,Ant语法 --> <excludes/> <!-- 排除的文件列表,Ant语法 --> </fileSet> </fileSets> <!-- 模块定义 --> <modules> <module id=.. dir=.. name=.. > <fileSets> <fileSet filtered=.. packaged=.. encoding=.. > <directory/> <includes/> <excludes/> </fileSet> </fileSets> <!-- 模块可以嵌套 --> <modules> <module>...recursion...<module> </modules> </module> </modules> </archetype-descriptor> |
下面是原型描述符的最小化示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?xml version="1.0" encoding="UTF-8"?> <archetype-descriptor name="basic"> <requiredProperties> <requiredProperty key="property-with-default"> <defaultValue>default-value</defaultValue> </requiredProperty> <requiredProperty key="property-without-default"/> </requiredProperties> <fileSets> <fileSet filtered="true" packaged="true"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> </fileSets> </archetype-descriptor> |
本节我们演示一下,如何从一个现有的项目,反向生成原型。
首先创建一个空白的Maven项目:
1 2 |
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.0 \ -DgroupId=cc.gmem.study.mvn -DartifactId=archetype-proto -DinteractiveMode=false |
进入示例项目,生成原型:
1 2 |
cd JavaEE/projects/idea/archetype-study/archetype-proto/ mvn archetype:create-from-project |
如果没有错误,生成的原型项目位于target/generated-sources/archetype目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
. └── archetype # 原型项目的根目录 ├── pom.xml # 原型项目的POM ├── src │ ├── main │ │ └── resources │ │ ├── archetype-resources # 原始项目的所有内容,亦即从此原型生成的项目的所有内容 │ │ │ ├── __artifactId__.iml │ │ │ ├── .idea │ │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── App.java # 注意包结构消失了 │ │ │ └── pom.xml │ │ └── META-INF │ │ └── maven │ │ └── archetype-metadata.xml # 原型元数据 │ └── test │ └── resources │ └── projects │ └── basic │ ├── archetype.properties # 用于测试原型 │ └── goal.txt └── target |
可以看到,上面的例子将原始项目的IDE元数据文件也放入到原型中了,这不是我们期望的,可以使用属性文件排除。
在原始项目中添加属性文件:
1 |
excludePatterns=.idea/** |
然后重新生成原型:
1 |
mvn clean archetype:create-from-project -Darchetype.properties=archetype.properties |
可以看到.idea目录被排除掉了。
从上面的例子还可以看到,生成的原型项目中App.java的包消失了。
实际上消失的是包前缀,它的值等于传递给create-from-project的package属性,如果不传递,则使用原始项目的包前缀。
生成的原型元数据中有如下片段:
1 2 3 4 5 6 |
<fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> |
其中package=true含义是,从原型生成项目时,archetype-resources/src/main/java中的内容会被包裹在$package指定的目录结构中。
在文件中添加一个配置:
1 |
application=App |
它的含义是,搜索原始项目的路径、文件中的文本,将App都更换为Application变量。对于本示例项目来说,其效果是:
- App.java的文件名替换为 __application__.java
- App.java中的类名被替换为 ${application}
这是一种简单粗暴的查找替换,使用时务必小心。
仍然使用上个例子,首先,构建并安装原型:
1 2 |
mvn clean archetype:create-from-project \ -Darchetype.properties=archetype.properties -Darchetype.postPhase=install |
本地原型目录会自动更新。
基于该原型创建一个新项目:
1 2 3 4 5 |
mvn archetype:generate -B -DarchetypeGroupId=cc.gmem.study.mvn \ -DarchetypeArtifactId=archetype-proto-archetype -DarchetypeVersion=1.0-SNAPSHOT \ -DgroupId=cc.gmem -DartifactId=project -Dversion=1.0-SNAPSHOT \ # 传递自定义属性 -Dpackage=cc.gmem.project -Dapplication=ProjectApp |
检查生成的项目, 可以看到目录结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
. └── project ├── archetype-metadata.yaml ├── pom.xml └── src └── main └── java └── cc └── gmem └── project ├── ProjectApp.java └── service └── ProjectAppService.java |
要在Maven中使用原型来生成项目骨架,必须依赖于maven-archetype-plugin。此插件依赖Java 7+版本,主流IDE内置了该插件。
maven-archetype-plugin使用Velocity作为模板引擎。
这是Maven原型项目的packaging,这种打包方式的生命周期绑定以下目标
- archetype:jar,绑定到package阶段,生成原型的JAR包
- archetype:integration-test,绑定到integration-test阶段
- archetype:update-local-catalog,绑定到install阶段,更新本地原型目录
从原型生成项目骨架:
- 如果从原型创建新的Maven项目,则输出到名为项目artifactId的目录
- 如果使用一个偏原型(partial archetype)更新已有项目,则输出到当前目录
用户需要从原型目录中选择一个原型,从远程仓库将原型拉取下来,然后生成项目。调用示例:
1 2 3 4 5 |
# -B表示批处理模式,等价于-DinteractiveMode=false mvn archetype:generate -B -DarchetypeGroupId=org.apache.maven.archetypes \ -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.1 \ -DgroupId=com.company -DartifactId=project -Dversion=1.0-SNAPSHOT \ -Dpackage=com.company.project |
其中通过-D传递的,是目标的参数。
可用参数包括:
参数 | 说明 |
interactiveMode | 是否以交互的方式生成 |
archetypeCatalog |
从哪个原型目录中读取原型:
|
archetypeGroupId | 从什么原型生成,原型的坐标 |
archetypeArtifactId | |
archetypeVersion | |
filter | 为显示的原型列表提供过滤器 |
goals | 在新生成的项目上执行的目标 |
outputDirectory | 输出目录 |
该目标用于从现有的项目(以下称原始项目)反向生成原型。它会读取项目中的源文件、资源文件,你通过.property指定的原型属性文件,并产生一个原型项目。原始项目中的文本文件会被转换为Velocity模板。
参数/属性 | 说明 |
archetypeFilteredExtentions |
检查哪些扩展名,以获取项目的文本文件 |
archetypeLanguages |
从什么目录来查项目的源码主包 |
archetypePostPhase |
在生成原型后,针对原型执行什么目标 默认package,可选package, integration-test, install, deploy |
defaultEncoding archetype.encoding |
Velocity模板的编码方式。默认UTF-8 |
interactive | 是否交互式的生成原型 |
keepParent archetype.keepParent |
从原型创建新的项目时,其POM中的parent引用和原始项目一致 |
outputDirectory | 原型项目的输出目录 |
packageName | 项目包名,原始项目文本文件中出现的packageName会被替换为Velocity变量 |
partialArchetype archetype.partialArchetype |
是否生成为偏模板 |
preserveCData archetype.preserveCData |
使用CDATA preservation来创建Velocity模板 |
propertyFile archetype.properties |
包含了此插件配置的属性文件,如果提供该参数,则创建会从中读取属性。默认值archetype.properties 属性分为两类:标准属性、定制属性 标准属性包括:
定制属性:你可以指定自己的定制属性,需要了解:
|
爬取文件系统中的Maven仓库,产生一个Maven原型目录文件。
Leave a Reply