. 前言
Maven ,发音是[`meivin] ," 专家" 的 意思。它是一个很好的项目管理工具,很早就进入了我的必备工具行列,但是这次为了把project1 项目完全迁移并应用maven ,所以对maven 进行 了一些深入的学习。写这个学习笔记的目的,一个是为了自己备忘,二则希望能够为其他人学习使用maven 缩短一些时间。
2. maven 概要
首先我把maven 的概念快速的梳理一下,让我们快速地建立起一个比较精确的maven 应用场景。
2.1 maven 不是什么
读书时候要先限定范围,避免一些有害的遐想。要说maven 不是什么,我们可以从如下几个要点来展开
2.2 maven 是什么
maven 将自己定位为一个项目管理工具。它负责管理项目开发过程中的几乎所有的东西:
2.3 maven 的生命周期
maven 把项目的构建划分为不同的生命周期(lifecycle) ,在我看来,划分的已经是非常仔细了,大家可以参考这里 。粗略一点的话,它这个过程(phase) 包括:编译、测试、打包、集成测试、验证、部署。maven 中所有的执行动作(goal) 都需要指明自己在这个过程中的执行位置,然后maven 执行的时候,就依照过程的发展依次调用这些goal 进行各种处理。
这个也是maven 的一个基本调度机制。一般来说,位置稍后的过程都会依赖于之前的过程。当然,maven 同样提供了配置文件,可以依照用户要求,跳过某些阶段。
2.4 maven 的" 约定优于配置"
所谓的" 约定优于配置" ,在maven 中并不是完全不可以修改的,他们只是一些配置的默认值而已。但是使用者除非必要,并不需要去修改那些约定内容。maven 默认的文件存放结构如下:
每一个阶段的任务都知道怎么正确完成自己的工作,比如compile 任务就知道从src/main/java 下编译所有的java 文件,并把它的输出class 文件存放到target/classes 中。
对maven 来说,采用" 约定优于配置" 的策略可以减少修改配置的工作量,也可以降低学习成本,更重要的是,给项目引入了统一的规范。
2.5 maven 的版本规范
maven 使用如下几个要素来唯一定位某一个输出物: groupId:artifactId:packaging:version 。比如 org.springframework:spring:2.5 。每个部分的解释如下:
maven 有自己的版本规范,一般是如下定义 <major version>.<minor version>.<incremental version>-<qualifier> ,比如1.2.3-beta-01 。要说明的是,maven 自己判断版本的算法是major,minor,incremental 部分用数字比 较,qualifier 部分用字符串比较,所以要小心 alpha-2 和alpha-15 的比较关系,最好用 alpha-02 的格式。
maven 在版本管理时候可以使用几个特殊的字符串 SNAPSHOT ,LATEST ,RELEASE 。比如"1.0-SNAPSHOT" 。各个部分的含义和处理逻辑如下说明:
2.6 maven 的组成部分
maven 把整个maven 管理的项目分为几个部分,一个部分是源代码,包括源代码本身、相关的各种资源,一个部分则是单元测试用例,另外一部分则是各种maven 的插件。对于这几个部分,maven 可以独立管理他们,包括各种外部依赖关系。
2.7 maven 的依赖管理
依赖管理一般是最吸引人使用maven 的功能特性了,这个特性让开发者只需要关注代码的直接依赖,比如我们用了spring ,就加入spring 依赖说明就可以了,至于spring 自己还依赖哪些外部的东西,maven 帮我们搞定。
任意一个外部依赖说明包含如下几个要素:groupId, artifactId, version, scope, type, optional 。其中前3 个是必须的,各自含义如下:
maven 认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven 中的依赖关系有作用域(scope) 的限制。在maven 中,scope 包含如下的取值:
另外,代码有代码自己的依赖,各个maven 使用的插件也可以有自己的依赖关系。依赖也可以是可选的,比如我们代码中没有任何cache 依赖,但是hibernate 可能要配置cache ,所以该cache 的依赖就是可选的。
2.8 多项目管理
maven 的多项目管理也是非常强大的。一般来说,maven 要求同一个工程的所有子项目都放置到同一个目录下,每一个子目录代表一个项目,比如
按照这种格式存放,就是继承方式,所有具体子项目的pom.xml 都会继承总项目pom 的内容,取值为子项目pom 内容优先。
要设置继承方式,首先要在总项目的pom 中加入如下配置
< modules > < module > simple-weather </ module > < module > simple-webapp </ module > </ modules >
其次在每个子项目中加入
< parent > < groupId > org.sonatype.mavenbook.ch06 </ groupId > < artifactId > simple-parent </ artifactId > < version > 1.0 </ version > </ parent >
即可。
当然,继承不是唯一的配置文件共用方式,maven 还支持引用方式。引用pom 的方式更简单,在依赖中加入一个type 为pom 的依赖即可。
< project > < description > This is a project requiring JDBC </ description > ... < dependencies > ... < dependency > < groupId > org.sonatype.mavenbook </ groupId > < artifactId > persistence-deps </ artifactId > < version > 1.0 </ version > < type > pom </ type > </ dependency > </ dependencies > </ project >
2.9 属性
用户可以在maven 中定义一些属性,然后在其他地方用${xxx} 进行引用。比如:
< project > < modelVersion > 4.0.0 </ modelVersion > ... < properties > < var1 > value1 </ var1 > </ properties > </ project >
maven 提供了三个隐式的变量,用来访问系统环境变量、POM 信息和maven 的settings :
2.10 maven 的profile
profile 是maven 的一个重要特性,它可以让maven 能够自动适应外部的环境变化,比如同一个项目,在linux 下编译linux 的版本,在win 下编译 win 的版本等。一个项目可以设置多个profile ,也可以在同一时间设置多个profile 被激活(active )的。自动激活的 profile 的条件可以是各种各样的设定条件,组合放置在activation 节点中,也可以通过命令行直接指定。profile 包含的其他配置内容可 以覆盖掉pom 定义的相应值。如果认为profile 设置比较复杂,可以将所有的profiles 内容移动到专门的 profiles.xml 文件中,不过记得和pom.xml 放在一起。
activation 节点中的激活条件中常见的有如下几个:
3. maven 的操作和使用
maven 的操作有两种方式,一种是通过mvn 命令行命令,一种是使用maven 的eclipse 插件。因为使用eclipse 的maven 插件操作起来比较容易,这里就只介绍使用mvn 命令行的操作。
3.1 maven 的配置文件
maven 的主执行程序为mvn.bat ,linux 下为mvn.sh ,这两个程序都很简单,它们的共同用途就是收集一些参数,然后用 java.exe 来运行maven 的Main 函数。maven 同样需要有配置文件,名字叫做settings.xml ,它放在两个地方,一个是maven 安装目录的conf 目录下,对所有使用该maven 的用户都起作用,我们称为主配置文件,另外一个放在 %USERPROFILE%/.m2/settings.xml 下,我们成为用户配置文件,只对当前用户有效,且可以覆盖主配置文件的参数内容。还有就是 项目级别的配置信息了,它存放在每一个maven 管理的项目目录下,叫pom.xml ,主要用于配置项目相关的一些内容,当然,如果有必要,用户也可以在 pom 中写一些配置,覆盖住配置文件和用户配置文件的设置参数内容。
一般来说,settings 文件配置的是比如repository 库路径之类的全局信息,具体可以参考官方网站的文章 。
3.2 创建新工程
要创建一个新的maven 工程,我们需要给我们的工程指定几个必要的要素,就是maven 产品坐标的几个要素:groupId, artifactId ,如果愿意,你也可以指定version 和package 名称。我们先看一个简单的创建命令:
d:\work\temp>mvn archetype:create -DgroupId=com.abc -DartifactId=product1 -DarchetypeArtifactId=maven-archetype-webapp
首先看这里的命令行参数的传递结构,怪异的 -D 参数= 值 的方式是 java.exe 要求的方式。这个命令创建一个web 工程,目录结构是一个标准的maven 结构,如下:
D:.
└─mywebapp
│ pom.xml
│
└─src
└─main
├─resources
└─webapp
│ index.jsp
│
└─WEB-INF
web.xml
大家要注意,这里目录结构的布局实际上是由参数 archetypeArtifactId 来决定的,因为这里传入的是 maven-archetype-webapp 如果我们传入其他的就会创建不同的结构,默认值为 maven-archetype-quickstart ,有兴趣的读者可以参考更详细的列表 ,我把部分常用的列表在这里:
Artifact |
Group |
Version |
Repository |
Description |
maven-archetype-j2ee-simple |
org.apache.maven.archetypes |
|
|
A simple J2EE Java application |
maven-archetype-marmalade-mojo |
org.apache.maven.archetypes |
|
|
A Maven plugin development project using marmalade |
maven-archetype-plugin |
org.apache.maven.archetypes |
|
|
A Maven Java plugin development project |
maven-archetype-portlet |
org.apache.maven.archetypes |
|
|
A simple portlet application |
maven-archetype-profiles |
org.apache.maven.archetypes |
|
|
|
maven-archetype-quickstart |
org.apache.maven.archetypes |
|
|
|
maven-archetype-simple |
org.apache.maven.archetypes |
|
|
|
maven-archetype-site-simple |
org.apache.maven.archetypes |
|
|
A simple site generation project |
maven-archetype-site |
org.apache.maven.archetypes |
|
|
A more complex site project |
maven-archetype-webapp |
org.apache.maven.archetypes |
|
|
A simple Java web application |
maven-archetype-har |
net.sf.maven-har |
0.9 |
|
Hibernate Archive |
maven-archetype-sar |
net.sf.maven-sar |
0.9 |
|
JBoss Service Archive |
大家可以参考更详细的 archetype:create 帮助 和 archtype参考信息 。
3.3 maven 的多项目管理
多项目管理是maven 的主要特色之一,对于一个大型工程,用maven 来管理他们之间复杂的依赖关系,是再好不过了。maven 的项目配置之间的关系有两种:继承关系和引用关系。
maven 默认根据目录结构来设定pom 的继承关系,即下级目录的pom 默认继承上级目录的pom 。要设定两者之间的关系很简单,上级pom 如下设置:
< modules > < module > ABCCommon </ module > < module > ABCCore </ module > < module > ABCTools </ module > </ modules >
要记住的是,这里的module 是目录名,不是子工程的artifactId 。子工程如下设置:
< parent > < groupId > com.abc.product1 </ groupId > < artifactId > abc-product1 </ artifactId > < version > 1.0.0-SNAPSHOT </ version > </ parent > < artifactId > abc-my-module2 </ artifactId > < packaging > jar </ packaging >
这样两者就相互关联起来了,继承关系就设定完毕,所有父工程的配置内容都会自动在子工程中生效,除非子工程有相同的配置覆盖。如果你不喜欢层层递进的目录结构来实现继承,也可以在parent 中加入 <relativePath>../a-parent/pom.xml</relativePath> 来制定parent 项目的相对目录。继承关系通常用在项目共同特性的抽取上,通过抽取公共特性,可以大幅度减少子项目的配置工作量。
引用关系是另外一种复用的方式,maven 中配置引用关系也很简单,加入一个 type 为 pom 的依赖即可。
< dependency > < groupId > org.sonatype.mavenbook </ groupId > < artifactId > persistence-deps </ artifactId > < version > 1.0 </ version > < type > pom </ type > </ dependency >
但是无论是父项目还是引用项目,这些工程都必须用 mvn install 或者 mvn deploy 安装到本地库才行,否则会报告依赖没有找到,eclipse 编译时候也会出错。
需要特别提出的是复用过程中,父项目的pom 中可以定义 dependencyManagement 节点,其中存放依赖关系,但是这个依赖关系只是定义,不会真的产生效果,如果子项目想要使用这个依赖关系,可以在本身的 dependency 中添加一个简化的引用
<dependency> <groupId> org.springframework </groupId> <artifactId> spring </artifactId> </dependency>
这种方法可以避免版本号满天飞的情况。
3.4 安装库文件到maven 库中
在maven 中一般都会用到安装库文件的功能,一则是我们常用的hibernate 要使用jmx 库,但是因为sun 的license 限制,所以无法将其直接包含在repository 中。所以我们使用mvn 命令把jar 安装到我们本地的repository 中
mvn install:install-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file
如果我们想把它安装到公司的repository 中,需要使用命令
mvn deploy:deploy-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=http://xxx.ss.com/sss.xxx -DrepositoryId=release-repo
对于我们的工程输出,如果需要放置到公司的repository 中的话,可以通过配置pom 来实现
<distributionManagement> <repository> <id> mycompany-repository </id> <name> MyCompany Repository </name> <url> scp://repository.mycompany.com/repository/maven2 </url> </repository> </distributionManagement>
这里使用的scp 方式提交库文件,还有其他方式可以使用,请参考faq 部分。然后记得在你的settings.xml 中加入这一内容
< settings xmlns ="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> ... < servers > < server > < id > mycompany-repository </ id > < username > jvanzyl </ username > <!-- Default value is ~/.ssh/id_dsa --> < privateKey > /path/to/identity </ privateKey > < passphrase > my_key_passphrase </ passphrase > </ server > </ servers > ... </ settings >
3.5 maven 的变量
maven 定义了很多变量属性, 参考这里 http://docs.codehaus.org/display/MAVENUSER/MavenPropertiesGuide
< project > ... < properties > < my.filter.value > hello </ my.filter.value > </ properties > ... </ project >
则引用 ${my.filter.value } 就会得到值 hello
3.6 maven 的使用
我们已经知道maven 预定义了许多的阶段(phase ),每个插件都依附于这些阶段,并且在进入某个阶段的时候,调用运行这些相关插件的功能。我们先来看完整的maven 生命周期:
生命周期 |
阶段描述 |
validate |
验证项目是否正确,以及所有为了完整构建必要的信息是否可用 |
generate-sources |
生成所有需要包含在编译过程中的源代码 |
process-sources |
处理源代码,比如过滤一些值 |
generate-resources |
生成所有需要包含在打包过程中的资源文件 |
process-resources |
复制并处理资源文件至目标目录,准备打包 |
compile |
编译项目的源代码 |
process-classes |
后处理编译生成的文件,例如对Java 类进行字节码增强(bytecode enhancement ) |
generate-test-sources |
生成所有包含在测试编译过程中的测试源码 |
process-test-sources |
处理测试源码,比如过滤一些值 |
generate-test-resources |
生成测试需要的资源文件 |
process-test-resources |
复制并处理测试资源文件至测试目标目录 |
test-compile |
编译测试源码至测试目标目录 |
test |
使用合适的单元测试框架运行测试。这些测试应该不需要代码被打包或发布 |
prepare-package |
在真正的打包之前,执行一些准备打包必要的操作。这通常会产生一个包的展开的处理过的版本(将会在Maven 2.1+ 中实现) |
package |
将编译好的代码打包成可分发的格式,如JAR ,WAR ,或者EAR |
pre-integration-test |
执行一些在集成测试运行之前需要的动作。如建立集成测试需要的环境 |
integration-test |
如果有必要的话,处理包并发布至集成测试可以运行的环境 |
post-integration-test |
执行一些在集成测试运行之后需要的动作。如清理集成测试环境。 |
verify |
执行所有检查,验证包是有效的,符合质量规范 |
install |
安装包至本地仓库,以备本地的其它项目作为依赖使用 |
deploy |
复制最终的包至远程仓库,共享给其它开发人员和项目(通常和一次正式的发布相关) |
maven 核心的插件列表可以参考 http://maven.apache.org/plugins/index.html 。这里仅列举几个常用的插件及其配置参数:
4. maven 的使用问答
除了以下的几个faq 条目之外,还有一些faq 可以参考
兄弟们如果有其他问题,欢迎跟帖提问!
4.1 依赖关系
1) 问:如何增加删除一个依赖关系?
答:直接在pom 文件中加入一个dependency 节点,如果要删除依赖,把对应的dependency 节点删除即可。
2) 问:如何屏蔽一个依赖关系?比如项目中使用的libA 依赖某个库的1.0 版,libB 以来某个库的2.0 版,现在想统一使用2.0 版,如何去掉1.0 版的依赖?
答:设置exclusion 即可。
< dependency > < groupId > org.hibernate </ groupId > < artifactId > hibernate </ artifactId > < version > 3.2.5.ga </ version > < exclusions > < exclusion > < groupId > javax.transaction </ groupId > < artifactId > jta </ artifactId > </ exclusion > </ exclusions > </ dependency >
3) 问:我有一些jar 文件要依赖,但是我又不想把这些jar 去install 到mvn 的repository 中去,怎么做配置?
答:加入一个特殊的依赖关系,使用system 类型,如下:
<dependency> <groupId> com.abc </ groupId> <artifactId> my-tools </ artifactId> <version> 2.5.0 </ version> <type> jar </ type> <scope> system </ scope> <systemPath> ${basedir}/lib/mylib1.jar </ systemPath> </ dependency>
但是要记住,发布的时候不会复制这个jar 。需要手工配置,而且其他project 依赖这个project 的时候,会报告警告。如果没有特殊要求,建议直接注册发布到repository 。
4) 问:在eclipse 环境中同时使用maven builder 和eclipse builder ,并且设置项目依赖关系之后,为什么编译会出现artifact 找不到错误,但是直接使用命令行mvn 构建则一切正常?
答:在project 属性中去掉java build path 中对其他 project 的依赖关系,直接在pom 中设置依赖关系即可
<!-- 依赖的其他项目 --> < dependency > < groupId > com.abc.project1 </ groupId > < artifactId > abc-project1-common </ artifactId > < version > ${project.version} </ version > </ dependency >
另外,保证没有其他错误。
5) 问:我想让输出的jar 包自动包含所有的依赖
答:使用 assembly 插件即可。
< plugin > < artifactId > maven-assembly-plugin </ artifactId > < configuration > < descriptorRefs > < descriptorRef > jar-with-dependencies </ descriptorRef > </ descriptorRefs > </ configuration > </ plugin >
6) 问:我的测试用例依赖于其他工程的测试用例,如何设置?
答:maven 本身在发布的时候,可以发布单纯的jar ,也可以同时发布xxx-tests.jar 和xxx-javadoc.jar (大家经常在repository 中可以看到类似的东西)。我们自己的项目A 要同时输出test.jar 可以做如下的设置
<!-- 用于把test 代码也做成一个jar --> < plugin > < groupId > org.apache.maven.plugins </ groupId > < artifactId > maven-jar-plugin </ artifactId > < executions > < execution > < goals > < goal > test-jar </ goal > </ goals > </ execution > </ executions > </ plugin >
然后在其他需要引用的工程B 中做如下的dependency 设置
< dependency > < groupId > com.abc.XXX </ groupId > < artifactId > 工程A </ artifactId > < version > ${project.version} </ version > < type > test-jar </ type > < scope > test </ scope > </ dependency >
7) 如何让maven 将工程依赖的jar 复制到WEB-INF/lib 目录下?
8) 我刚刚更新了一下我的nexus 库,但是我无法在eclipse 中用m2eclipse 找到我新增的库文件
修改pom.xml 文件,将旧版jar 的依赖内容中的版本直接修改为新版本即可。
9 )我要的jar 最新版不在maven 的中央库中,我怎么办?
将依赖的文件安装到本地库,用如下命令可以完成:
10 )
4.2 变量
1) 问:如何使用变量替换?项目中的某个配置文件比如jdbc.properties 使用了一些pom 中的变量,如何在发布中使用包含真实内容的最终结果文件?
答:使用资源过滤功能,比如:
< project > ... < properties > < jdbc.driverClassName > com.mysql.jdbc.Driver </ jdbc.driverClassName > < jdbc.url > jdbc:mysql://localhost:3306/development_db </ jdbc.url > < jdbc.username > dev_user </ jdbc.username > < jdbc.password > s3cr3tw0rd </ jdbc.password > </ properties > ... < build > < resources > < resource > < directory > src/main/resources </ directory > < filtering > true </ filtering > </ resource > </ resources > </ build > ... < profiles > < profile > < id > production </ id > < properties > < jdbc.driverClassName > oracle.jdbc.driver.OracleDriver </ jdbc.driverClassName > < jdbc.url > jdbc:oracle:thin:@proddb01:1521:PROD </ jdbc.url > < jdbc.username > prod_user </ jdbc.username > < jdbc.password > s00p3rs3cr3t </ jdbc.password > </ properties > </ profile > </ profiles > </ project >
2) 问: maven-svn-revision-number-plugin 插件说明
答: maven-svn-revision-number-plugin 可以从 SVN 中获取版本号,并将其变成环境变量,交由其他插件或者profile 使用,详细帮助在这里 。一般和resource 的filter 机制同时使用
< plugins > < plugin > < groupId > com.google.code.maven-svn-revision-number-plugin </ groupId > < artifactId > maven-svn-revision-number-plugin </ artifactId > < version > 1.3 </ version > < executions > < execution > < goals > < goal > revision </ goal > </ goals > </ execution > </ executions > < configuration > < entries > < entry > < prefix > prefix </ prefix > </ entry > </ entries > </ configuration > </ plugin > </ plugins >
这段代码负责把resource 文件中的内容替换成适当内容
3 )我的程序有些单元测试有错误,如何忽略测试步骤?
有好几种方法都可以实现跳过单元测试步骤,一种是给mvn 增加命令行参数 -Dmaven.test.skip=true 或者 -DskipTests=true ;另外一种是给surefire 插件增加参数,如下:
<project> [...] <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.8</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build> [...] </project>
4) 如果只想运行单个测试用例,能否实现?
可以,运行时候增加命令行参数 -Dtest=MyTest 即可,其中MyTest 是所需要运行的单元测试用例名称,但是不需要包含package 部分。
4.3 编译
1) 问:如何给插件指派参数?比如我要设置一些编译参数
答:以下内容设定编译器编译java1.5 的代码
< project > ... < build > ... < plugins > < plugin > < artifactId > maven-compiler-plugin </ artifactId > < configuration > < source > 1.5 </ source > < target > 1.5 </ target > </ configuration > </ plugin > </ plugins > ... </ build > ... </ project >
要设置其他插件的参数也可以,请参考对应插件的帮助信息
2) 问:我的目录是非标准的目录结构,如何设置让maven 支持?
答:指定source 目录和test-source 目录即可。
< build > < directory > target </ directory > < sourceDirectory > src </ sourceDirectory > < scriptSourceDirectory > js/scripts </ scriptSourceDirectory > < testSourceDirectory > test </ testSourceDirectory > < outputDirectory > bin </ outputDirectory > < testOutputDirectory > bin </ testOutputDirectory > </ build >
这个例子把源代码设置成了src 目录,测试代码在test 目录,所以输出到bin 目录。这里要注意,directory 如果也设置成bin 目录的 话,maven 打包的时候会引起死循环,因为directory 是所有工作存放的地方,默认包含outputDirectory 定义的目录在内。
3) 我源代码是UTF8 格式的,我如何在maven 中指定?
设置一个变量即可
< project > ... < properties > < project.build.sourceEncoding > UTF-8 </ project.build.sourceEncoding > </ properties > ... </ project >
以上是官方给出的解决方案,但是经过尝试这样只能影响到resource 处理时候的编码 ,真正有用的是如下配置:
<build> ... <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> ... </build>
. 问:我的项目除了main/java 目录之外,还加了其他的c++ 目录,想要一并编译,如何做?
答:使用native 插件,具体配置方法参考[http://mojo.codehaus.org/maven-native/native-maven-plugin/]
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>native-maven-plugin</artifactId> <extensions>true</extensions> <configuration> </plugin>
. 问:我想要把工程的所有依赖的jar 都一起打包,怎么办?
答:首先修改maven 的配置文件,给maven-assembly-plugin 增加一个jar-with-dependencies 的描述。
<project> [...] <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> [...] </project>
然后使用命令打包即可:
mvn assembly:assembly
. 问:我想把main/scripts 中的内容一起打包发布,如何做?
答:在pom 中配置额外的资源目录。如果需要的话,还可以指定资源目录的输出位置
<build> ... <resources> <resource> <filtering>true</filtering> <directory>src/main/command</directory> <includes> <include>run.bat</include> <include>run.sh</include> </includes> <targetPath>/abc</targetPath> </resource> <resource> <directory>src/main/scripts</directory> </resource> </resources> ... </build>
. 问:我有多个源代码目录,但是maven 只支持一个main src 和一个test src ,怎么办?
答:使用另外一个插件,并仿照如下配置pom
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.1</version> <executions> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>src/config/java</source> <source>src/main/java</source> <source>src/member/java</source> </sources> </configuration> </execution> </executions> </plugin>
. 问:我的源代码目录中有一部分文件我不想让maven 编译,怎么做?
答:使用一个maven 插件,然后使用includes 和excludes 。同理,也可以处理资源的过滤。
<build> <sourceDirectory>http://www.cnblogs.com/src/java</sourceDirectory> <plugins> <plugin> <groupId>com.sun.enterprise</groupId> <artifactId>hk2-maven-plugin</artifactId> <configuration> <includes> <include>com/sun/logging/LogDomains.*</include> <include>com/sun/enterprise/util/OS.java</include> <include>com/sun/enterprise/util/io/FileUtils.java</include> <include>com/sun/enterprise/util/zip/**</include> <include>com/sun/enterprise/util/i18n/**</include> <include>com/sun/enterprise/deployment/backend/IASDeploymentException.java</include> </includes> <excludes> <exclude>com/sun/enterprise/config/ConfigBeansFactory.java</exclude> <exclude>com/sun/enterprise/config/clientbeans/**</exclude> </excludes> </configuration> </plugin> </plugins> <resources> <resource> <directory>http://www.cnblogs.com/src/java</directory> <includes> <include>**/*.properties</include> </includes> </resource> </resources> </build>
. 问:我的项目是一个纯的html 组成的项目,没有任何的java 代码,怎么跳过编译过程?
答:配置如下
<build> <sourceDirectory>src/java</sourceDirectory> <plugins> <plugin> <groupId>com.sun.enterprise</groupId> <artifactId>hk2-maven-plugin</artifactId> </plugin> </plugins> </build>
. 问:我的工程里用hibernate ,想在编译时候自动生成ddl ,如何做?
答:添加插件
hibernate3-maven-plugin
,按照如下配置:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.1</version> <configuration> <components> <component> <name>hbm2ddl</name> <implementation>annotationconfiguration</implementation> </component> </components> </configuration> <dependencies> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>${hsqldb.version}</version> </dependency> </dependencies> </plugin>
. 问:我能用maven 支持eclipse RCP 项目吗?
答:当然可以,你可以使用插件 Tycho ,详细内容可以参考这里[http://mattiasholmqvist.se/2010/02/building-with-tycho-part-1-osgi-bundles/ ].
<plugin> <groupid>org.sonatype.tycho</groupid> <artifactid>target-platform-configuration</artifactid> <version>0.7.0</version> <configuration> <resolver>p2</resolver> </configuration> </plugin>
另外,老牌的pde-maven-plugin 就不要用了,已经好几年没见更新了。
4.4 ant 互动
1) 如何在maven 编译时候运行ant 脚本?
使用专门的antrun 插件,并且在target 标签内部加入ant 的代码
<plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.6</version> <executions> <execution> <phase> <!-- 生命周期阶段 --> </phase> <configuration> <target> <!-- 加入target 内部的代码 --> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin>
2 )如何在ant 脚本中引用maven 的classpath ?
maven 给每一个依赖都生成了一个属性,格式为"groupId:artifactId[:classifier]:type" ,比如,如果一下例子就显示依赖的org.apache.common-util 的jar 文件路径
<echo message="Dependency JAR Path: ${org.apache:common-util:jar}"/>
另外,maven 还预定义了四个classpath 的引用,他们是
3 )如何使用antrun 插件运行外部的build 文件?
很简单,直接在antrun 里边使用ant 指令即可,如下:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.6</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <configuration> <target> <!-- 同时传递内置的classpath 给外部ant 文件 --> <property name="compile_classpath" refid="maven.compile.classpath"/> <property name="runtime_classpath" refid="maven.runtime.classpath"/> <property name="test_classpath" refid="maven.test.classpath"/> <property name="plugin_classpath" refid="maven.plugin.classpath"/> <ant antfile="${basedir}/build.xml"> <target name="test"/> </ant> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin>
. 问:如何在ant 中使用maven 的功能?
答:使用ant 的[maven task|http://maven.apache.org/ant-tasks/index.html] ,不过只有ant 1.6 以上和jdk 1.5 环境才支持。
h4. 测试相关
. 问:如何忽略某个阶段的结果?比如单元测试不一定要全正确
答:给插件增加testFailureIgnore 参数,并设置为false 。如果要屏蔽该阶段,则用
<skip>true</skip> <project> [...] <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> </plugins> </build> [...] </project>
. 问:我如何在maven 中加入PMD ,CheckStyle ,JDepend 等检查功能?
答:加入PMD 检查,以下代码如果在
reporting
节点中加入则在
mvn site
中执行,如果在
build
节点中加入,则在build 的时候自动运行检查。详细配置参考[pmd 插件使用说明|http://maven.apache.org/plugins/maven-pmd-plugin/]
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>2.5</version> </plugin> </plugins>
加入 checkstyle 检查,详细配置参考[checkstyle 插件使用说明|http://maven.apache.org/plugins/maven- checkstyle-plugin/] ,同样注意放置在reporting 和build 节点中的区别(所有报表类插件都要同样注意):
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <version>2.5</version> </plugin>
加入 simian 的支持,simian 是一个支持代码相似度检查的工具,目前有maven 插件,也有checkstyle 的插件。它不仅可以检查java ,甚至可以支持文 本文件的检查。详细帮助信息参考[ 这里|http://www.redhillconsulting.com.au/products/simian /] 。simian 的 maven 插件在[ 这里|http://mojo.codehaus.org/simian-report-maven-plugin /introduction.html]
<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>simian-maven-plugin</artifactId> <version>1.6.1</version> </plugin> </plugins> ... </build>
加入 jdepend 检查,详细配置参考[jdepend 使用说明|http://mojo.codehaus.org/jdepend-maven-plugin/] ,
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jdepend-maven-plugin</artifactId> <version>2.0-beta-2</version> </plugin>
加入 findbugz 检查,详细配置参考[findbugz 使用说明|http://mojo.codehaus.org/findbugs-maven-plugin/usage.html] ,
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> <version>2.0.1</version> </plugin>
加入javadoc 生成,详细配置参考[javadoc usage|http://maven.apache.org/plugins/maven-javadoc-plugin/usage.html]
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>2.7</version> <configuration> ... </configuration> </plugin>
加入 jxr 支持,JXR 是一个生成java 代码交叉引用和源代码的html 格式的工具,详细配置信息参考[jxr usage|http://maven.apache.org/plugins/maven-jxr-plugin/] 。注意,jxr 没有必要在 build 阶段运行。
<reporting> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jxr-plugin</artifactId> <version>2.1</version> </plugin> </plugins> </reporting>
加入 Cobertura 支持,它是一个代码覆盖率工具,可以用来评估具有相应测试的源代码的比率。详细帮助在[ 这里|http://mojo.codehaus.org /cobertura-maven-plugin/index.html] 。另外一个功能相似的软件是[EMMA|http: //emma.sourceforge.net/samples.html], 详细的帮助在[ 这里|http://mojo.codehaus.org /emma-maven-plugin/usage.html] 。两个产品的比较文章在[ 这里|http://www.topcoder.com /tc?module=Static&d1=features&d2=030107] ,个人倾向于都要用,因为给出的指标不一样,都有参 考作用。
Cobertura
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>cobertura-maven-plugin</artifactId> <version>2.4</version> <configuration> <check> <branchRate>85</branchRate> <lineRate>85</lineRate> <haltOnFailure>true</haltOnFailure> <totalBranchRate>85</totalBranchRate> <totalLineRate>85</totalLineRate> <packageLineRate>85</packageLineRate> <packageBranchRate>85</packageBranchRate> <regexes> <regex> <pattern>com.example.reallyimportant.*</pattern> <branchRate>90</branchRate> <lineRate>80</lineRate> </regex> <regex> <pattern>com.example.boringcode.*</pattern> <branchRate>40</branchRate> <lineRate>30</lineRate> </regex> </regexes> </check> </configuration> <executions> <execution> <goals> <goal>clean</goal> <goal>check</goal> </goals> </execution> </executions> </plugin>
EMMA
<reporting> ... <plugins> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>emma-maven-plugin</artifactId> <version>1.0-alpha-3-SNAPSHOT</version> </plugin> ... </plugins> ... </reporting>
添加 javaNCSS 插件,它是一个java 代码的度量工具,详细参考在[ 这里|http://mojo.codehaus.org/javancss-maven-plugin/] 。
<reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>javancss-maven-plugin</artifactId> <version>2.0-beta-2</version> </plugin> </plugins> </reporting>
h4. profile 相关
. 问:profile 能够设置为某个变量不存在的条件下激活?
答:使用!前缀,请看示例:
<activation> <property> <name>!environment.type</name> </property> </activation>
h4. 部署相关
. 问:其他部署到服务器的方式和配置怎么配?
答:本文摘自 [http://blog.csdn.net/zyxnetxz/archive/2009/05/18/4199348.aspx]{panel} *Distribution Management* 用于配置分发管理,配置相应的产品发布信息, 主要用于发布,在执行mvn deploy 后表示要发布的位置 *# 配置到文件系统
<distributionManagement> <repository> <id>proficio-repository<id> <name>Proficio Repository<name> <url>file://${basedir}/target/deploy<url> <repository> <distributionManagement>
*# 使用ssh2 配置
<distributionManagement> <repository> <id>proficio-repository<id> <name>Proficio Repository<name> <url>scp://sshserver.yourcompany.com/deploy<url> <repository> <distributionManagement>
*# 使用sftp 配置
<distributionManagement> <repository> <id>proficio-repositoryi<d> <name>Proficio Repository<name> <url>sftp://ftpserver.yourcompany.com/deploy<url> <repository> <distributionManagement>
*# 使用外在的ssh 配置编译扩展用于指定使用wagon 外在ssh 提供,用于提供你的文件到相应的远程服务器。
<distributionManagement> <repository> <id>proficio-repository<id> <name>Proficio Repository<name> <url>scpexe://sshserver.yourcompany.com/deploy<url> <repository> <distributionManagement> <build> <extensions> <extension> <groupId>org.apache.maven.wagon<groupId> <artifactId>wagon-ssh-external<artifactId> <version>1.0-alpha-6<version> <extension> <extensions> <build>
*# 使用ftp 配置
<distributionManagement> <repository> <id>proficio-repository<id> <name>Proficio Repository<name> <url>ftp://ftpserver.yourcompany.com/deploy<url> <repository> <distributionManagement> <build> <extensions> <extension> <groupId>org.apache.maven.wagongroupId> <artifactId>wagon-ftpartifactId> <version>1.0-alpha-6version> <extension> <extensions> </build>
. 问:我用maven 输出site ,如何设置输出为utf8 编码?
答: 配置site 插件的编码设置
... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> <version>2.0-beta-6</version> <configuration> <outputEncoding>UTF-8</outputEncoding> </configuration> </plugin> ...