Arch-05-13- maven常见问题问答
maven常见问题问答http://www.cnblogs.com/BigTall/archive/2011/03/23/1993253.html
?
1.前言
Maven,发音是[`meivin],"专家"的意思。它是一个很好的项目管理工具,很早就进入了我的必备工具行列,但是这次为了把project1项目完全迁移并应用maven,所以对maven进行了一些深入的学习。写这个学习笔记的目的,一个是为了自己备忘,二则希望能够为其他人学习使用maven 缩短一些时间。
2. maven概要
首先我把maven的概念快速的梳理一下,让我们快速地建立起一个比较精确的maven应用场景。
2.1 maven不是什么
读书时候要先限定范围,避免一些有害的遐想。要说maven不是什么,我们可以从如下几个要点来展开
- maven不是ant,也不是make。?
我们以前接触的构建工具,需要写一些详细的步骤,比如:?compile project1/src/*.java?等类似的语句。这些语句正是我们使用ant和make所要编写的东西。maven采用了"约定优于配置"的方法,一些开发常用的操作和步骤已经固化在 maven中,所以使用者不再需要去编写那些烦人的语句了。同时,maven内置了开发流程的支持,它不仅能够编译,同样能够打包、发布,也能够一气呵成做完这些所有的步骤。 - maven不是ivy?
依赖管理是maven的功能之一,虽然很多人包括我以前都是只用它的依赖管理功能,但是要深入运用的话,我们就可以看到更多的内容。更重要的是,maven在依赖关系中加入了scope的概念,进一步细化了依赖关系的划分。
2.2 maven是什么
maven将自己定位为一个项目管理工具。它负责管理项目开发过程中的几乎所有的东西:
- 版本?
maven有自己的版本定义和规则 - 构建?
maven支持许多种的应用程序类型,对于每一种支持的应用程序类型都定义好了一组构建规则和工具集。 - 输出物管理?
maven可以管理项目构建的产物,并将其加入到用户库中。这个功能可以用于项目组和其他部门之间的交付行为。 - 依赖关系?
maven对依赖关系的特性进行细致的分析和划分,避免开发过程中的依赖混乱和相互污染行为 - 文档和构建结果?
maven的site命令支持各种文档信息的发布,包括构建过程的各种输出,javadoc,产品文档等。 - 项目关系?
一个大型的项目通常有几个小项目或者模块组成,用maven可以很方便地管理 - 移植性管理?
maven可以针对不同的开发场景,输出不同种类的输出结果。
2.3 maven的生命周期
maven把项目的构建划分为不同的生命周期(lifecycle),在我看来,划分的已经是非常仔细了,大家可以参考这里?。粗略一点的话,它这个过程(phase)包括:编译、测试、打包、集成测试、验证、部署。maven中所有的执行动作(goal)都需要指明自己在这个过程中的执行位置,然后maven执行的时候,就依照过程的发展依次调用这些goal进行各种处理。
这个也是maven的一个基本调度机制。一般来说,位置稍后的过程都会依赖于之前的过程。当然,maven同样提供了配置文件,可以依照用户要求,跳过某些阶段。
2.4 maven的"约定优于配置"
所谓的"约定优于配置",在maven中并不是完全不可以修改的,他们只是一些配置的默认值而已。但是使用者除非必要,并不需要去修改那些约定内容。maven默认的文件存放结构如下:
- /项目目录
- pom.xml 用于maven的配置文件
- /src 源代码目录
- /src/main 工程源代码目录
- /src/main/java 工程java源代码目录
- /src/main/resource 工程的资源目录
- /src/test 单元测试目录
- /src/test/java
- /target 输出目录,所有的输出物都存放在这个目录下
- /target/classes 编译之后的class文件
每一个阶段的任务都知道怎么正确完成自己的工作,比如compile任务就知道从src/main/java下编译所有的java文件,并把它的输出class文件存放到target/classes中。
对maven来说,采用"约定优于配置"的策略可以减少修改配置的工作量,也可以降低学习成本,更重要的是,给项目引入了统一的规范。
2.5 maven的版本规范
maven使用如下几个要素来唯一定位某一个输出物:?groupId:artifactId:packaging:version?。比如?org.springframework:spring:2.5?。每个部分的解释如下:
- groupId?
团体,公司,小组,组织,项目,或者其它团体。团体标识的约定是,它以创建这个项目的组织名称的逆向域名(reverse domain name)开头。来自Sonatype的项目有一个以com.sonatype开头的groupId,而Apache Software的项目有以org.apache开头的groupId。 - artifactId?
在groupId下的表示一个单独项目的唯一标识符。比如我们的tomcat, commons等。不要在artifactId中包含点号(.)。 - version?
一个项目的特定版本。发布的项目有一个固定的版本标识来指向该项目的某一个特定的版本。而正在开发中的项目可以用一个特殊的标识,这种标识给版本加上一个"SNAPSHOT"的标记。?
虽然项目的打包格式也是Maven坐标的重要组成部分,但是它不是项目唯一标识符的一个部分。一个项目的 groupId:artifactId:version使之成为一个独一无二的项目;你不能同时有一个拥有同样的groupId, artifactId和version标识的项目。 - packaging?
项目的类型,默认是jar,描述了项目打包后的输出。类型为jar的项目产生一个JAR文件,类型为war的项目产生一个web应用。 - classifier?
很少使用的坐标,一般都可以忽略classifiers。如果你要发布同样的代码,但是由于技术原因需要生成两个单独的构件,你就要使用一个分类器(classifier)。例如,如果你想要构建两个单独的构件成JAR,一个使用Java 1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件,它们有同样的groupId:artifactId:version组合。如果你的项目使用本地扩展类库,你可以使用分类器为每一个目标平台生成一个构件。分类器常用于打包构件的源码,JavaDoc或者二进制集合。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"。各个部分的含义和处理逻辑如下说明:
- SNAPSHOT?
如果一个版本包含字符串"SNAPSHOT",Maven就会在安装或发布这个组件的时候将该符号展开为一个日期和时间值,转换为UTC时间。例如,"1.0-SNAPSHOT"会在2010年5月5日下午2点10分发布时候变成1.0-20100505-141000-1。?
这个词只能用于开发过程中,因为一般来说,项目组都会频繁发布一些版本,最后实际发布的时候,会在这些snapshot版本中寻找一个稳定的,用于正式发布,比如1.4版本发布之前,就会有一系列的1.4-SNAPSHOT,而实际发布的1.4,也是从中拿出来的一个稳定版。 - LATEST?
指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个snapshot版,具体看哪个时间最后。 - RELEASE?
指最后一个发布版。2.6 maven的组成部分
maven把整个maven管理的项目分为几个部分,一个部分是源代码,包括源代码本身、相关的各种资源,一个部分则是单元测试用例,另外一部分则是各种maven的插件。对于这几个部分,maven可以独立管理他们,包括各种外部依赖关系。
2.7 maven的依赖管理
依赖管理一般是最吸引人使用maven的功能特性了,这个特性让开发者只需要关注代码的直接依赖,比如我们用了spring,就加入spring依赖说明就可以了,至于spring自己还依赖哪些外部的东西,maven帮我们搞定。
任意一个外部依赖说明包含如下几个要素:groupId, artifactId, version, scope, type, optional。其中前3个是必须的,各自含义如下:
- groupId 必须
- artifactId 必须
- version 必须。?
这里的version可以用区间表达式来表示,比如(2.0,)表示>2.0,[2.0,3.0)表示2.0<=ver<3.0;多个条件之间用逗号分隔,比如[1,3),[5,7]。 - scope 作用域限制
- type 一般在pom引用依赖时候出现,其他时候不用
- optional 是否可选依赖
maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。在maven中,scope包含如下的取值:
- compile(编译范围)?
compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。编译范围依赖在所有的classpath中可用,同时它们也会被打包。 - provided(已提供范围)?
provided依赖只有在当JDK或者一个容器已提供该依赖之后才使用。例如,如果你开发了一个web应用,你可能在编译classpath中需要可用的Servlet API来编译一个servlet,但是你不会想要在打包好的WAR中包含这个Servlet API;这个Servlet API JAR由你的应用服务器或者servlet容器提供。已提供范围的依赖在编译classpath(不是运行时)可用。它们不是传递性的,也不会被打包。 - runtime(运行时范围)?
runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现。 - test(测试范围)?
test范围依赖 在一般的 编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。测试范围依赖在之前的???中介绍过。 - system(系统范围)?
system范围依赖与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven也不会在仓库中去寻找它。?如果你将一个依赖范围设置成系统范围,你必须同时提供一个systemPath元素?。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的Maven仓库中引用依赖)。另外,代码有代码自己的依赖,各个maven使用的插件也可以有自己的依赖关系。依赖也可以是可选的,比如我们代码中没有任何cache依赖,但是hibernate可能要配置cache,所以该cache的依赖就是可选的。
2.8 多项目管理
maven的多项目管理也是非常强大的。一般来说,maven要求同一个工程的所有子项目都放置到同一个目录下,每一个子目录代表一个项目,比如
- 总项目/
- pom.xml 总项目的pom配置文件
- 子项目1/
- pom.xml 子项目1的pom文件
- 子项目2/
- pom.xml 子项目2的pom文件
按照这种格式存放,就是继承方式,所有具体子项目的pom.xml都会继承总项目pom的内容,取值为子项目pom内容优先。
要设置继承方式,首先要在总项目的pom中加入如下配置
${pom.project.build.directory?} - ${project.build.?outputD?irectory?}?results in the path to your "target/classes" dir
- ${project.name?} refers to the name of the project.
- ${project.version?} refers to the version of the project.
- ${project.build.finalName?} refers to the final name of the file created when the built project is packaged
- 本地用户设定?
所有用的的 settings.xml 中的设定都可以通过?settings.?前缀进行引用- ${settings.localRepository?} refers to the path of the user's local repository.
- ${maven.repo.local?} also works for backward compatibility with maven1 ??
- 环境变量?
系统的环境变量通过?env.?前缀引用- ${env.M2_HOME?} returns the Maven2 installation path.
- ${java.home?} specifies the path to the current JRE_HOME environment use with relative paths to get for example:?
<jvm>${java.home}../bin/java.exe</jvm> - java系统属性?
所有JVM中定义的java系统属性. - 用户在pom中定义的自定义属性>
. 问:如何在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>
{code:xml}<project> [...] <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> </plugins> </build> [...]</project>{code}. 问:我如何在maven中加入PMD,CheckStyle,JDepend等检查功能?答:加入PMD检查,以下代码如果在
reporting
节点中加入则在mvn site
中执行,如果在build
节点中加入,则在build的时候自动运行检查。详细配置参考[pmd插件使用说明|http://maven.apache.org/plugins/maven-pmd-plugin/]{code:xml} <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>2.5</version> </plugin> </plugins>{code}加入 checkstyle 检查,详细配置参考[checkstyle插件使用说明|http://maven.apache.org/plugins/maven-checkstyle-plugin/],同样注意放置在reporting和build节点中的区别(所有报表类插件都要同样注意):{code:xml} <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> <version>2.5</version> </plugin>{code}加入 simian 的支持,simian是一个支持代码相似度检查的工具,目前有maven插件,也有checkstyle的插件。它不仅可以检查java,甚至可以支持文本文件的检查。详细帮助信息参考[这里|http://www.redhillconsulting.com.au/products/simian/]。simian 的 maven插件在[这里|http://mojo.codehaus.org/simian-report-maven-plugin/introduction.html]{code:xml} <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>simian-maven-plugin</artifactId> <version>1.6.1</version> </plugin> </plugins> ... </build>{code}加入 jdepend 检查,详细配置参考[jdepend使用说明|http://mojo.codehaus.org/jdepend-maven-plugin/],{code:xml} <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jdepend-maven-plugin</artifactId> <version>2.0-beta-2</version> </plugin>{code}加入 findbugz 检查,详细配置参考[findbugz使用说明|http://mojo.codehaus.org/findbugs-maven-plugin/usage.html],{code:xml} <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> <version>2.0.1</version> </plugin>{code}加入javadoc生成,详细配置参考[javadoc usage|http://maven.apache.org/plugins/maven-javadoc-plugin/usage.html]{code:xml} <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>2.7</version> <configuration> ... </configuration> </plugin>{code}加入 jxr 支持,JXR是一个生成java代码交叉引用和源代码的html格式的工具,详细配置信息参考[jxr usage|http://maven.apache.org/plugins/maven-jxr-plugin/]。注意,jxr没有必要在build阶段运行。{code:xml} <reporting> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jxr-plugin</artifactId> <version>2.1</version> </plugin> </plugins> </reporting>{code}加入 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],个人倾向于都要用,因为给出的指标不一样,都有参考作用。{code:xml|title=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>{code}{code:xml|title=EMMA} <reporting> ... <plugins> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>emma-maven-plugin</artifactId> <version>1.0-alpha-3-SNAPSHOT</version> </plugin> ... </plugins> ... </reporting>{code}添加 javaNCSS 插件,它是一个java代码的度量工具,详细参考在[这里|http://mojo.codehaus.org/javancss-maven-plugin/]。{code:xml} <reporting> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>javancss-maven-plugin</artifactId> <version>2.0-beta-2</version> </plugin> </plugins> </reporting>{code}h4. profile相关. 问:profile能够设置为某个变量不存在的条件下激活?答:使用!前缀,请看示例:
{code:xml}<activation> <property> <name>!environment.type</name> </property> </activation>{code}h4. 部署相关. 问:其他部署到服务器的方式和配置怎么配?答:本文摘自 [http://blog.csdn.net/zyxnetxz/archive/2009/05/18/4199348.aspx]{panel} *Distribution Management* 用于配置分发管理,配置相应的产品发布信息,主要用于发布,在执行mvn deploy后表示要发布的位置 *# 配置到文件系统
{code:xml}<distributionManagement> <repository> <id>proficio-repository<id> <name>Proficio Repository<name> <url>file://${basedir}/target/deploy<url> <repository><distributionManagement>{code}*# 使用ssh2配置{code:xml}<distributionManagement> <repository> <id>proficio-repository<id> <name>Proficio Repository<name> <url>scp://sshserver.yourcompany.com/deploy<url> <repository><distributionManagement>{code}*# 使用sftp配置{code:xml}<distributionManagement> <repository> <id>proficio-repositoryi<d> <name>Proficio Repository<name> <url>sftp://ftpserver.yourcompany.com/deploy<url> <repository><distributionManagement>{code}*# 使用外在的ssh配置编译扩展用于指定使用wagon外在ssh提供,用于提供你的文件到相应的远程服务器。{code:xml}<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>{code}*# 使用ftp配置{code:xml}<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>{code}{panel} h4. 插件配置. 问:我用maven输出site,如何设置输出为utf8编码?答: 配置site插件的编码设置
{code:xml}... <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> ...{code}
- pom.xml 子项目2的pom文件
- 总项目/
- compile(编译范围)?
- SNAPSHOT?
- groupId?
- /target/classes 编译之后的class文件
- /src/main 工程源代码目录