01. maven 概要
首先我把 maven 的概念快速的梳理一下,让我们快速地建立起一个比较精确的 maven 应用场景。
maven 不是 ant,也不是 make,以前接触的构建工具,需要写一些详细的步骤,如: compile project1/src/*.java 等类似的语句。
maven 采用了"约定优于配置"的方法,一些开发常用的操作和步骤已经固化在 maven中,所以使用者不再需要编写那些语句。
maven 内置了开发流程的支持,它不仅能够编译,同样能够打包、发布,也能够一气呵成做完这些所有的步骤。
maven 不是 ivy,依赖管理是 maven 的功能之一,maven 在依赖关系中加入了scope 的概念,进一步细化了依赖关系的划分。
maven 将自己定位为一个项目管理工具。它负责管理项目开发过程中的如下几乎所有的东西。
a.版本:maven有自己的版本定义和规则;
b.构建:maven支持许多种的应用程序类型,对于每一种支持的应用程序类型都定义好了一组构建规则和工具集;
c.输出物管理:maven可以管理项目构建的产物,并将其加入到用户库中。这个功能可以用于项目组和其他部门之间的交付行为;
d.依赖关系 : maven对依赖关系的特性进行细致的分析和划分,避免开发过程中的依赖混乱和相互污染行为;
e.文档和构建结果:maven的site命令支持各种文档信息的发布,包括构建过程的各种输出,javadoc,产品文档等;
f.项目关系:一个大型的项目通常有几个小项目或者模块组成,用maven可以很方便地管理;
h.移植性管理 : maven可以针对不同的开发场景,输出不同种类的输出结果;
更多介绍请移步到:http://yanan0628.iteye.com/blog/2270344
02. maven 生命周期
maven把项目的构建划分为不同的生命周期(lifecycle),包括:验证、编译、测试、打包、集成测试、部署。
maven中所有的执行动作(goal)都需要指明自己在这个过程中的执行位置,然后maven执行的时候,就依照过程的发展依次调用这些goal进行各种处理。
这个也是maven的一个基本调度机制。一般来说,位置稍后的过程都会依赖于之前的过程。
当然,maven同样提供配置文件,可以依照用户要求,跳过某些阶段。
03. 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来说,采用"约定优于配置"的策略可以减少修改配置的工作量,也可以降低学习成本,更重要的是,给项目引入了统一的规范。
04. maven的版本规范
<groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.7.RELEASE</version>
maven 使用如下几个要素来唯一定位某一个输出物: groupId:artifactId:packaging:version 。如org.springframework:spring:2.5 。
groupId 团体,公司,小组,组织,项目,或者其它团体。团体标识的约定是,它以创建这个项目的组织名称的逆向域名(reverse domain name)开头。
artifactId 在groupId下的表示一个单独项目的唯一标识符。比如我们的tomcat, commons等。不要在artifactId中包含点号(.)。
version 一个项目的特定版本。发布的项目有一个固定的版本标识来指向该项目的某一个特定的版本。而正在开发中的项目可以用一个特殊的标识,这种标识给版本加上一个"SNAPSHOT"的标记。
虽然项目的打包格式也是 Maven 坐标的重要组成部分,但是它不是项目唯一标识符的一个部分。
一个项目的 groupId:artifactId:version 使之成为一个独一无二的项目;你不能同时有一个拥有同样的 groupId, artifactId和version标识的项目。
packaging 项目的类型,默认是jar,描述了项目打包后的输出。类型为jar的项目产生一个JAR文件,类型为war的项目产生一个web应用。
maven在版本管理时候可以使用几个特殊的字符串 SNAPSHOT ,LATEST ,RELEASE 。比如"1.0-SNAPSHOT"。各个部分的含义和处理逻辑如下说明:
SNAPSHOT:如果一个版本包含字符串"SNAPSHOT",用于开发过程,Maven就会在安装或发布这个组件的时候将该符号展开为一个日期和时间值,转换为UTC时间。
例如,"1.0-SNAPSHOT"会在2010年5月5日下午2点10分发布时候变成1.0-20100505-141000-1。
LATEST:指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个snapshot版,具体看哪个时间最后。
RELEASE:指最后一个发布版。
maven把整个maven管理的项目分为几个部分,一个部分是源代码,包括源代码本身、相关的各种资源,一个部分则是单元测试用例,另外一部分则是各种maven的插件。
05. maven的依赖管理
依赖管理一般是最吸引人使用 maven 的功能特性,这个特性让开发者只需要关注代码的直接依赖。
比如我们用了spring,就加入spring依赖说明就可以了,至于spring自己还依赖哪些外部的东西,maven帮我们搞定。
任意一个外部依赖说明包含如下几个要素:groupId, artifactId, version, scope, type, optional。其中前3个是必须的,各自含义如下:
这里的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的依赖就是可选的。
06. maven 多项目管理
maven的多项目管理也是非常强大的。一般来说,maven要求同一个工程的所有子项目都放置到同一个目录下,每一个子目录代表一个项目,比如
总项目/ pom.xml 总项目的pom配置文件
子项目1/pom.xml 子项目1的pom文件
子项目2/ pom.xml 子项目2的pom文件
按照这种格式存放,就是继承方式,所有具体子项目的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>
07. maven 内置属性
用户可以在maven中定义一些属性,然后在其他地方用${xxx}进行引用。比如:
<project> <modelVersion>4.0.0</modelVersion> ... <properties> <var1>value1</var1> </properties> </project>
maven提供了三个隐式的变量,用来访问系统环境变量、POM信息和maven的settings:
env 暴露操作系统的环境变量,比如env.PATH
project 暴露POM中的内容,用点号(.)的路径来引用POM元素的值,比如${project.artifactId}。另外,java的系统属性比如user.dir等,也暴露在这里。
settings 暴露maven的settings的信息,也可以用点号(.)来引用。
maven把系统配置文件存放在maven的安装目录中,把用户相关的配置文件存放在~/.m2/settings.xml(unix)或 者%USERPROFILE%/.m2/settings.xml(windows)中。
08. maven 的profile
profile是maven的一个重要特性,它可以让maven能够自动适应外部的环境变化,比如同一个项目,在linux下编译linux的版本,在win下编译win的版本等。
一个项目可以设置多个profile,也可以在同一时间设置多个profile被激活(active)的。
自动激活的 profile的条件可以是各种各样的设定条件,组合放置在activation节点中,也可以通过命令行直接指定。
profile包含的其他配置内容可以覆盖掉pom定义的相应值。如果认为profile设置比较复杂,可以将所有的profiles内容移动到专门的 profiles.xml 文件中,不过记得和pom.xml放在一起。
09. 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库路径之类的全局信息,具体可以参考官方网站的文章。
10. maven 安装库文件到 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>
11. maven 常用命令
1. 创建Maven的普通java项目: mvn archetype:create -DgroupId=packageName -DartifactId=projectName 2. 创建Maven的Web项目: mvn archetype:create -DgroupId=packageName -DartifactId=webappName -DarchetypeArtifactId=maven-archetype-webapp 3. 编译源代码: mvn compile 4. 编译测试代码:mvn test-compile 5. 运行测试:mvn test 6. 产生site:mvn site 7. 打包:mvn package 8. 在本地Repository中安装jar:mvn install 9. 清除产生的项目:mvn clean 10. 生成eclipse项目:mvn eclipse:eclipse 11. 生成idea项目:mvn idea:idea 12. 组合使用goal命令,如只打包不测试:mvn -Dtest package 13. 编译测试的内容:mvn test-compile 14. 只打jar包: mvn jar:jar 15. 只测试而不编译,也不测试编译:mvn test -skipping compile -skipping test-compile ( -skipping 的灵活运用,当然也可以用于其他组合命令) 16. 清除eclipse的一些系统设置:mvn eclipse:clean