Maven配置
配置
环境变量M2_HOME
指向安装根目录。
模板的位置在:$M2_HOME/conf/settings.xml
。
配置文件位置:~/.m2/conf/settings.xml
。
检查安装是否成功:
mvn -v
如果有输出版本信息就安装正确。
查看帮助,如果是第一次运行就会下载到本地仓库:
mvn help:system
HTTP代理
官方中央库:repo1.maven.org
如果要用代理,在settings.xml
中加上:
<proxies> <proxy> <id>my-proxy</id> <active>true</active> <protocol>http</protocol> <host>218.14.227.197</host> <port>3128</port> <!-- <username>username</username> <password>p@ssw0rd</password> <nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts> --> </proxy> <proxy> ... </proxy> </proxies>
proxy可以有多个,第一个是默认的。
maven属性
内置属性
-
${basedir}
-
${version}
POM属性
-
${project.groupId}
-
${project.artifactId}
-
${project.version}
-
${project.build.finalName}
:project.artifactId-project.version -
${project.build.sourceDirectory}
:src/main/java -
${project.build.testSourceDirectory}
:src/test/java -
${project.build.directory}
:target -
${project.outputDirectory}
:target/classes -
${project.testOutputDirectory}
:target/test-classes
其他属性
-
settings.xml
中的值,如:${settings.localRepository}
是本地仓库。 -
Java系统属性:如
user.home
-
系统环境变量:如
${env.JAVA_HOME}
,通过mvn help:system
查看
XML中定义属性
<project> ... <properties> <myprop>hello</myprop> </properties> ... </project>
建立工程
配置工程目录结构
如果不用默认的目录结构,要自定义的话:
<build> <!-- Java 源代码的路径配置 --> <sourceDirectory>src/main/java</sourceDirectory> <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory> <!-- 测试代码的路径配置 --> <testSourceDirectory>src/test/java</testSourceDirectory> <!-- 源码编译后的 class 文件的路径配置 --> <outputDirectory>target/classes</outputDirectory> <!-- 测试源码编译后的 class 文件的路径配置 --> <testOutputDirectory>target/test-classes</testOutputDirectory> <plugin> .... </plugin> </build>
Archetype生成项目骨架
列出各种工程的模块,然后选一个:
mvn archetype:generate
先会让先生成框架工具的版本,就用默认最新的maven-archetype-quickstart
就可以了
。然后按向导输入信息。
包管理
坐标
-
groupId
-
artifactId
-
version
-
packaging
:默认为jar
-
classifier
:不可配置,由附加插件生成。如一个包可以有附加的源代码包或文档包。
依赖配置
依赖 | 编译时需要 | 测试时需要 | 运行时需要 | 例子 |
---|---|---|---|---|
compile | Y | Y | Y | spring-core |
test | Y | JUnit | ||
provided | Y | Y | servlet-api | |
runtime | Y | Y | JDBC的实现,如:MySQL-driver | |
system | Y | Y | 与本机系统绑定不通过Maven仓库依赖 |
system级别的依赖必须通过systemPath
元素显式指定依赖文件的路径。systemPath
元素
可以引用环境变量,如:
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jar</systemPath> </dependency>
传递依赖
compile | test | provided | runtime | |
---|---|---|---|---|
compile | compile | runtime | ||
test | test | test | ||
provided | provided | provided | provided | |
runtime | runtime | runtime |
例子:
- greenmail直接compile依赖javax.mail(上表第一列)
- 我们的MailApp直接test依赖greenmail(上表第二行)
- 那么MailApp对javax.mail的依赖就是test(交叉位置)
可选依赖
比如某工具包对于JDBC驱动实现,有MySQL和PostgreSQL等。但其他应用引用这个工具包时 ,只会依赖一种数据库:
<dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> <optional>true</optional> </dependency> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.4-701.jdbc3</version> <optional>true</optional> </dependency> </dependencies>
其他项目在用到上面这个包时,如果用的是mysql,就要显式声明依赖
mysql-connector-java
。
可选依赖是一个不推荐的实现,违反了单一性原则。推荐的做法是对MySQL和PostgreSQL 分别搞两个包。
优化依赖
-
查看已经解析的依赖:
mvn dependency:list
-
树形展示依赖:
mvn dependency:tree
-
分析依赖:
mvn dependency:analyze
,显示结果:-
Used undeclared dependencies
,已经用到,没有显式声明。应该显式声明出来。 -
unused declared dependencies
,声明了但是没有用。注意只是没有编译依赖, 可能会有运行和测试依赖,所以不一字能去掉。
-
导出包
把maven项目中的jar包复制出来,导出到默认目录targed/dependency
:
dependency:copy-dependencies
指定输出的目录:
dependency:copy-dependencies -DoutputDirectory=lib
指定信赖的级别:
dependency:copy-dependencies -DoutputDirectory=lib -DincludeScope=compile
仓库
本地仓库
~/.m2/settings.xml
中定义本地仓库的位置:
<settings> <localRepository>/myfolder/m2/repository</localRepository> </settings>
把项目发布到本地仓库:mvn clean install
打包时跳过单元测试:
mvn install -Dmaven.test.skip=true
远程仓库
中央仓库
$M@_HOME/lib/maven-model-builder-3.0.jar
中配置文件
org/apache/maven/model/pom-4.0.0.xml
是所有Maven项目都会继承的超级POM,里面
定义了中央仓库的信息:
... <repository> <id>central</id> <url>http://repo1.maven.org/maven2</url> ... </repository> ...
配置远程仓库
比如要增加JBOSS的仓库,那么在pom.xml
中加上:
<project> ... <repositories> <repository> <id>jboss</id> <name>JBoss Repository</name> <url>http://repository.jboss.com</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>daily</updatePolicy> <checksunPolicy>ignore</checksunPolicy> </snapshots> <layout>default</layout> </repository> </repositories> ... </project>
-
id
必须唯一,重名了会被覆盖。如:定义了一个叫central
的就会把maven默认的 中央库给替换掉。 -
release
是否下载正式发布的版本。 -
snapshots
是否下载开发中的快照版本,如果为true
,就还要另外指定:-
updatePolicy
:检查更新频率:never
、daily
、interval: x
每隔x分钟、always
每次构建都检查。 -
checksumPolicy
:检验文件:ignore
、warn
、fail
。
-
远程仓库认证
仓库信息可以直接放在pom.xml
中,但认证信息一定要放在settings.xml
里。
以一个id为my-proj
的仓库的认证信息为例:
<settings> ... <servers> <server> <id>my-proj</id> <username>repo-user</username> <password>repo-pwd</password> </server> </servers> ... </settings>
部署到远程仓库
配置pom.xml
中的distributionManagement
元素:
<project> ... <distributemanagement> <repository> <id>proj-releases</id> <name>Proj Release Repository</name> <url>http://192.168.1.100/content/repository/proj-releases</url> </repository> <snapshotRepository> <id>proj-snapshots</id> <name>Proj Snapshot Repository</name> <url>http://192.168.1.100/content/repository/proj-snapshots</url> </snapshotRepository> </distributemanagement> ... </project>
这里分别定义了快照和发布版本的库,要布署到远程库使用命令:
mvn clean deploy
包的版本
Range | Meaning |
---|---|
1.0 | x >= 1.0 推荐 1.0 ,但也可以用1.0以上的版本 |
(,1.0] | x <= 1.0 |
(,1.0) | x < 1.0 |
[1.0] | x == 1.0 |
[1.0,) | x >= 1.0 |
(1.0,) | x > 1.0 |
(1.0,2.0) | 1.0 < x < 2.0 |
[1.0,2.0] | 1.0 <= x <= 2.0 |
(,1.0],[1.2,) | x <= 1.0 or x >= 1.2. Multiple sets are comma-separated |
(,1.1),(1.1,) | x != 1.1 |
快照版本
虽然更新快照的频率可以通过updatePolicy控制,但也可以强制检查更新。例:
mvn clean update -U
Maven会检查仓库的元数据groupid/artifactId/version/maven-metadata.xml
:
<metadata> <versioning> <groupId>org.sonatype.nexus</groupId> <artifactId>nexus</artifactId> <version>1.4.2-SNAPSHOT</version> <snapshot> <timestamp>20091214.221414</timestamp> <buildNumber>13</buildNumber> </snapshot> </versioning> </metadata>
如果元数据出错了,可能就无法解析,这时就要通过手工或工具(如Nexus)修复。
LAST 和 RELEASE 版本
Maven 3 已经不支持 LAST 和 REALSE 版本。如果不指定包的版本,会默认使用最新的 版本,但在实践中不推荐这样做。
镜像
http://maven.net.cn/content/groups/public/就是中央库在中国的一个镜像。可以 用来替换中央库:
<settings> ... <mirrors> <mirror> <id>maven.net.cn</id> <name>one of the central mirrors in chia</name> <url>http://maven.net.cn/content/groups/public</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> ... </settings>
central
表示任何对中央库的请求会被转到这里。
私服作为镜像
例:用一个私服作为所有远程仓库的镜像:
<settings> ... <mirrors> <mirror> <id>maven.net.cn</id> <name>one of the central mirrors in chia</name> <url>http://maven.net.cn/content/groups/public</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> ... </settings>
-
<mirrorOf>*</mirrorOf>
:匹配所有的远程仓库。 -
<mirrorOf>external:*</mirrorOf>
:除了本机上使用file://
协议的 -
<mirrorOf>repo1,repo2</mirrorOf>
:匹配指定 -
<mirrorOf>#,! repo1</mirrorOf>
:匹配除了指定以外的
注意镜像是屏蔽远程对象的,所以镜像服务器坏了就连不了了。
仓库搜索服务
- http://repository.sonatype.org
- http:www.jarvana.com/jarvana
- http:www.mvnbrowser.com
- http:mvnrepository.com
生命周期
maven把构建过程分成大周期,每个周期下又有多个阶段。
-
clean:前期清理与准备工作。
- pre-clean
- clean
- post-clean
-
default:编译与生成包。
- validate
- initialize
- generate-sources
- process-sources
- generate-resources
- process-resources
- compile
- process-classes
- generate-test-sources
- process-test-sources
- generate-test-resource
- process-test-resource
- test-compile
- process-test-classes
- test
- prepare-package
- package
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install
- deploy
-
site:生成与应用相关的文档。
- pre-site
- site
- post-site
- site-deploy
生命周期与插件的绑定
maven本身不进行构建操作,而是通过在不同时间调用不同的插件完成构建工作。
各阶段的默认绑定
clean:
生命阶段 | 插件目标 |
---|---|
pre-clean | |
clean | maven-clean-plugin:clean |
post-clean |
site:
生命阶段 | 插件目标 |
---|---|
pre-site | |
site | maven-site-plugin:site |
post-site | |
site-deploy | maven-site-plugin:deploy |
default:
生命阶段 | 插件目标 | 任务 |
---|---|---|
process-sources | maven-resources-plugin:resources | 复制资源文件到主输出目录 |
compiles | maven--plugin:compile | 编译程序文件到主输出目录 |
generate-test-sourcess | maven-resources-plugin:testResources | 复制测试资源文件到测试主输出目录 |
test-compiles | maven--plugin:testCompile | 编译测试程序文件到测试主输出目录 |
tests | maven-surefire-plugin:test | 执行测试用例 |
packages | maven-jar-plugin:jar | 创建jar包 |
installs | maven-install-plugin:install | 部署到本地仓库 |
deploys | maven-deploy-plugin:deploy | 部署到过程仓库 |
自定义绑定
比如把源代码打包的任务没有默认绑定,这时手动绑定到default的verify阶段:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <id>attach-sources</id> <phase>verify</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
executions下的每个execution子元素都可以配置一个任务。这里的attach-sources
任务
,phase指定阶段为verify
,goals指定目标为jar-no-fork
。执行:
mvn verify
就算是删除掉phase一行,也有默认的绑定阶段。可以通过以下命令查看插件目标的 默认绑定阶段:
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:2.1.1- -Ddetail
插件配置
命令行参数配置
命令行参数配置的方式是:-D参数=值
有些参数适合从命令行配置,比如maven-surefire-plugin当maven.test.skip=true
时
跳过测试:
mvn install -Dmaven.test.skip=true
POM文件中全局配置
在configuration
下。比如scala-maven-plugin,指定编译参数和运行参数:
<plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <configuration> <scalaVersion>${scala.version}</scalaVersion> <jvmArgs> <jvmArg>-client</jvmArg> <jvmArg>-Xms64m</jvmArg> <jvmArg>-Xmx1024m</jvmArg> </jvmArgs> <launchers> <launcher> <id>foo</id> <mainClass>example.ScalaAppExample</mainClass> <args> <arg>Hello</arg> <arg>World</arg> </args> </launcher> </launchers> </configuration> ... </plugin>
POM中任务配置
在execution
下。比如scala-maven-plugin,指定运行任务:
<plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> ... <executions> <execution><!-- do "scala:compile" when "compile" --> <id>compile-scala</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution><!-- do "scala:testCompile" when "test-compile" --> <id>compile-scala-test</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin>
使用maven-help-plugin插件来描述插件
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-compiler-plugin:2.1.1 -Ddetail
可以简化只坐标:
mvn help:describe -Dplugin=compiler
还可以指定目标,比如查看与compile目标相关:
mvn help:describe -Dplugin=compiler -Dgoal=compile
聚合和继承
聚合
有很多个工程不用一个一个构建,让一个工程聚集其他多个工程,然后一起构建。
-
packaging类型必须为
pom
-
用
module
指定聚合的工程
<project> <modelVersion>4.0.0</modelVersion> <groupId>jade.jadeutils</groupId> <artifactId>jadeutils-parent</artifactId> <version>2.0.0</version> <packaging>pom</packaging> <name>jade utils parent</name> <modules> <module>../jadeutils-base</module> <module>../jadeutils-cache</module> <module>../jadeutils-dao</module> <module>../jadeutils-web</module> <module>../jadeutils-image</module> <module>../jadeutils-sandtable</module> <module>../jadeutils-cdn</module> </modules> ... </project>
继承
-
packaging类型必须为
pom
-
子项目中通过
parent
指定父项目 -
relativePath
可以在不通过仓库的情况下找到父pom。如果省略就一定要在本地仓库 里有父项目。
<parent> <groupId>jade.jadeutils</groupId> <artifactId>jadeutils-parent</artifactId> <version>2.0.0</version> <relativePath>../jadeutils-parent/pom.xml</relativePath> </parent>
可以继承的元素有:
- groupId
- version
- description
- organization
- inceptionYear
- url
- developers
- contributors
- distributionManagement
- issueManagement
- ciManagement:项目持续集成系统信息
- scm:版本管理系统
- mailingLists
- properties:自定义的Maven属性
- dependencies
- dependencyManagement
- repositories
- build
- reporting
父项目中进行依赖管理:
<dependencyManagement> <dependencies> <dependency> <!-- common log --> <groupId>org.slf4j</groupId> <artifactId>slf4j-jcl</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <!-- jdk log --> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>${slf4j.version}</version> </dependency> </dependencies> </dependencyManagement>
父项目中进行插件管理:
<project> ... <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </pluginManagement> </build> ... </project>
反应堆
用户开发的不同子模块之间相互依赖,形成一个依赖的反应堆。形式应该是一个 有向非循环图(Directed Acyclic Graph, DAG)。如果有环形依赖Maven会报错。
裁剪反应堆
通过mvn -h
查看帮助。
指定构建的模块,参数-pl
、--projects
,用逗号分隔:
vmcn clean install -pl account-email, account-persist
构建指定模块和它所依赖的模块,参数-am
、--also-make
:
vmcn clean install -pl account-email -am
构建指定模块和依赖于它的模块,参数-amd
、--also-make-dependents
:
vmcn clean install -pl account-parent -amd
在反应堆构建顺序上指定从哪个模块开始构建,参数rf
、resume-from
:
vmcn clean install -rf account-parent -amd
可以把条件组合起来:
vmcn clean install -pl account-parent -amd -rf account-email
编译
任务
-
clean:clean
-
compiler:compiler
-
compiler:testCompile
以clean:clean
为例,代表的意思是clean插件的clean目标,其他类似。
支持Java 5
默认只支持Java 1.3,要配置才能支持更高版本:
<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>utf8</encoding> </configuration> </plugin> </pluginManagement> </build>
打包
任务
-
package
:默认生成的是Jar包。 -
install:install
MANIFEST.MF
如果是可运行的带main()
方法的jar包,还要生成对应的MANIFEST.MF
文件:
<project ... > ... <build> ... <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.3</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class>example.ScalaAppExample</Main-Class> <Build-Number>123</Build-Number> </manifestEntries> </transformer> </transformers> </configuration> </plugin> </plugins> ... </project>
在manifestEntries
里以key-value形式添加内容。以上为例就是:
- Main-Class: example.ScalaAppExample
- Build_number: 123
这样会生成两个jar包:
-
hello-1.0-SNAPSHOT.jar
:有Main-Class
可运行。 -
original-hello-1.0-SNAPSHOT.jar
:没有Main-Class
,不可运行。
运行
运行Java的main方法
Without arguments:
mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main"
With arguments:
mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main" -Dexec.args="arg0 arg1 arg2"
With runtime dependencies in the CLASSPATH:
mvn exec:java -Dexec.mainClass="com.vineetmanohar.module.Main" -Dexec.classpathScope=runtime
Running in a phase in pom.xml
You can also run the main method in a maven phase. For example, you can run the CodeGenerator.main() method as part of the test phase.
<build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.1.1</version> <executions> <execution> <phase>test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>com.vineetmanohar.module.CodeGenerator</mainClass> <arguments> <argument>arg0</argument> <argument>arg1</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build>
Running in a profile in pom.xml
You can also run the main method in a different profile. Simply wrap the above config in the <profile> tag.
<profiles> <profile> <id>code-generator</id> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.1.1</version> <executions> <execution> <phase>test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>com.vineetmanohar.module.CodeGenerator</mainClass> <arguments> <argument>arg0</argument> <argument>arg1</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles>
常用任务
-
resources:resources
-
resources:testResources
JVM参数
参数加在MAVEN_OPTS
中,比如内存大小的分配:
set MAVEN_OPTS= -Xms128m -Xmx512m #
初始化
mvn help:system