转载地址:https://blog.csdn.net/u012152619/article/details/51473380
(一)Maven是什么
首先,Maven的正确发音是[ˈmevən],而不是“马瘟”以及其他什么瘟。Maven在美国是一个口语化的词语,代表专家、内行的意思,约等于北京话中的老炮儿。
一个对Maven比较正式的定义是这么说的:Maven是一个项目管理工具,它包含了一个项目对象模型 (POM:Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。
不过,这段话对于完全没有Maven实践经验的人来说,看了等于没看,并没有什么卵用。
Maven到底是什么,能做什么,可以用更通俗的方式来说明。我们知道,项目开发不仅仅是写写代码而已,期间会伴随着各种必不可少的事情要做,下面列举几个感受一下:
1、我们需要引用各种jar包,尤其是比较大的工程,引用的jar包往往有几十个乃至上百个, 每用到一种jar包,都需要手动引入工程目录,而且经常遇到各种让人抓狂的jar包冲突,版本冲突。
2、我们辛辛苦苦写好了Java文件,可是只懂0和1的白痴电脑却完全读不懂,需要将它编译成二进制字节码。好歹现在这项工作可以由各种集成开发工具帮我们完成,Eclipse、IDEA等都可以将代码即时编译。当然,如果你嫌生命漫长,何不铺张,也可以用记事本来敲代码,然后用javac命令一个个地去编译,逗电脑玩。
3、世界上没有不存在bug的代码,正如世界上没有不喜欢美女的男人一样。写完了代码,我们还要写一些单元测试,然后一个个的运行来检验代码质量。
4、再优雅的代码也是要出来卖的。我们后面还需要把代码与各种配置文件、资源整合到一起,定型打包,如果是web项目,还需要将之发布到服务器,供人蹂躏。
试想,如果现在有一种工具,可以把你从上面的繁琐工作中解放出来,能帮你构建工程,管理jar包,编译代码,还能帮你自动运行单元测试,打包,生成报表,甚至能帮你部署项目,生成Web站点,你会心动吗?傻子才不会。
负责任的告诉你,以上的一切Maven都可以办到。概括地说,Maven可以简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝连接。
(二)Maven生命周期
我们在开发项目的时候,不断地在编译、测试、打包、部署等过程,maven的生命周期就是对所有构建过程抽象与统一,生命周期包含项目的清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成等几乎所有的过程。
Maven有三套相互独立的生命周期,请注意这里说的是“三套”,而且“相互独立”,初学者容易将Maven的生命周期看成一个整体,其实不然。这三套生命周期分别是:
• CleanLifecycle 在进行真正的构建之前进行一些清理工作。
• DefaultLifecycle 构建的核心部分,编译,测试,打包,部署等等。
• SiteLifecycle 生成项目报告,站点,发布站点。
再次强调一下它们是相互独立的,可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然也可以直接运行 “mvn clean install site” 运行所有这三套生命周期。
每套生命周期都由一组阶段(Phase)组成,我们平时在命令行输入的命令总会对应于一个特定的阶段。maven中所有的执行动作(goal)都需要指明自己在这个过程中的执行位置,然后maven执行的时候,就依照过程的发展依次调用这些goal进行各种处理。这个也是maven的一个基本调度机制。
每套生命周期还可以细分成多个阶段。
Clean生命周期
Clean生命周期一共包含了三个阶段:
Clean生命周期
pre-clean
执行一些需要在clean之前完成的工作
clean
移除所有上一次构建生成的文件
post-clean
执行一些需要在clean之后立刻完成的工作
命令“mvn clean”中的就是代表执行上面的clean阶段,在一个生命周期中,运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,“mvn clean” 等同于 “mvn pre-clean clean” ,如果我们运行“mvn post-clean” ,那么 “pre-clean”,“clean” 都会被运行。这是Maven很重要的一个规则,可以大大简化命令行的输入。
Default生命周期
Maven最重要就是的Default生命周期,也称构建生命周期,绝大部分工作都发生在这个生命周期中,每个阶段的名称与功能如下::
Default生命周期
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
在真正的打包之前,执行一些准备打包必要的操
作
package
将编译好的代码打包成可分发的格式,如
JAR,WAR,或者EAR
pre-integration-test
执行一些在集成测试运行之前需要的动作。如建
立集成测试需要的环境
integration-test
如果有必要的话,处理包并发布至集成测试可以
运行的环境
post-integration-test
执行一些在集成测试运行之后需要的动作。如清
理集成测试环境。
verify
执行所有检查,验证包是有效的,符合质量规范
install
安装包至本地仓库,以备本地的其它项目作为依
赖使用
deploy
复制最终的包至远程仓库,共享给其它开发人员
和项目(通常和一次正式的发布相关)
可见,构建生命周期被细分成了22个阶段,但是我们没必要对每个阶段都了如指掌,经常关联使用的只有process-test-resources、test、package、install、deploy等几个阶段而已。
一般来说,位置稍后的过程都会依赖于之前的过程。这也就是为什么我们运行“mvn install” 的时候,代码会被编译,测试,打包。当然,maven同样提供了配置文件,可以依照用户要求,跳过某些阶段。比如有时候希望跳过测试阶段而直接install,因为单元测试如果有任何一条没通过,maven就会终止后续的工作。
Site生命周期
Site生命周期
pre-site
执行一些需要在生成站点文档之前完成的工作
site
生成项目的站点文档
post-site
执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
site-deploy
将生成的站点文档部署到特定的服务器上
这里经常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点,这是Maven相当强大的功能。
(三)Maven插件
Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,像编译是通过maven-compile-plugin实现的、测试是通过maven-surefire-plugin实现的,maven也内置了很多插件,所以我们在项目进行编译、测试、打包的过程是没有感觉到。
进一步说,每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如maven-compiler-plugin的compile目标用来编译位于src/main/java/目录下的主源码,testCompile目标用来编译位于src/test/java/目录下的测试源码。
认识上述Maven插件的基本概念能帮助你理解Maven的工作机制,不过要想更高效率地使用Maven,了解一些常用的插件还是很有必要的,这可以帮助你避免一不小心重新发明轮子。多年来Maven社区积累了大量的经验,并随之形成了一个成熟的插件生态圈。Maven官方有两个插件列表,第一个列表的GroupId为org.apache.maven.plugins,这里的插件最为成熟,具体地址为:http://maven.apache.org/plugins/index.html。第二个列表的GroupId为org.codehaus.mojo,这里的插件没有那么核心,但也有不少十分有用,其地址为:http://mojo.codehaus.org/plugins.html。
下面列举了一些常用的核心插件,每个插件的如何配置,官方网站都有详细的介绍。
一个插件通常提供了一组目标,可使用以下语法来执行:
mvn [plugin-name]:[goal-name]
例如,一个Java项目使用了编译器插件,通过运行以下命令编译
mvn compiler:compile
Maven提供以下两种类型的插件:
l 构建插件
在生成过程中执行,并应在pom.xml中的<build/>元素进行配置
l 报告插件
在网站生成期间执行的,应该在pom.xml中的<reporting/>元素进行配置。
这里仅列举几个常用的插件,每个插件的如何进行个性化配置在官网都有详细的介绍。
除了这些核心插件之外,还有很多优秀的第三方插件,可以帮助我们快捷、方便的构架项目。当使用到某些功能或者特性的时候多加搜索,往往得到让你惊喜的效果。
<plugins> <plugin> <!-- 编译插件 --> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-compiler-plugin </artifactId> <version>2.3.2 </version> <configuration> <source>1.5 </source> <target>1.5 </target> </configuration> </plugin> <plugin> <!-- 发布插件 --> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-deploy-plugin </artifactId> <version>2.5 </version> </plugin> <plugin> <!-- 打包插件 --> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-jar-plugin </artifactId> <version>2.3.1 </version> </plugin> <plugin> <!-- 安装插件 --> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-install-plugin </artifactId> <version>2.3.1 </version> </plugin> <plugin> <!-- 单元测试插件 --> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-surefire-plugin </artifactId> <version>2.7.2 </version> <configuration> <skip>true </skip> </configuration> </plugin> <plugin> <!-- 源码插件 --> <groupId>org.apache.maven.plugins </groupId> <artifactId>maven-source-plugin </artifactId> <version>2.1 </version> <!-- 发布时自动将源码同时发布的配置 --> <executions> <execution> <id>attach-sources </id> <goals> <goal>jar </goal> </goals> </execution> </executions> </plugin> </plugins>例如,项目中使用了Mybatis,就有一款神奇的maven插件,运行一个命令,就可以根据数据库的表,自动生成Mybatis的mapper配置文件以及DAO层接口模板。
在pom.xml中添加plugin:
<plugin> <groupId>org.mybatis.generator </groupId> <artifactId>mybatis-generator-maven-plugin </artifactId> <version>1.3.2 </version> <configuration> <configurationFile>src/main/resources/mybatis-generator/generatorConfig.xml </configurationFile> <verbose>true </verbose> <overwrite>true </overwrite> </configuration> <executions> <execution> <id>Generate MyBatis Artifacts </id> <goals> <goal>generate </goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.mybatis.generator </groupId> <artifactId>mybatis-generator-core </artifactId> <version>1.3.2 </version> </dependency> </dependencies> </plugin>定义generatorConfig.xml配置文件:
"1.0" encoding="UTF-8" xml version= <generatorConfiguration> <classPathEntry location="/Users/winner/mysql/mysql-connector-java-5.1.36.jar"/> <context id="DB2Tables" targetRuntime="MyBatis3"> <!-- 去掉自动生成的注解 --> <commentGenerator> <property name="suppressAllComments" value="true"/> </commentGenerator> < jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3344/db?characterEncoding=utf8" userId="id" password="password"> </jdbcConnection> <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer true,把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成映射类--> <javaModelGenerator targetPackage="com.clf.model" targetProject="/Users/winner/Documents/workspace/project/src/main/java/"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- 生成xml文件--> <sqlMapGenerator targetPackage="com.clf.mapper" targetProject="/Users/winner/Documents/workspace/project/src/main/resources/"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </sqlMapGenerator> <!-- 生成mapperinterface--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.clf.mapper" targetProject="/Users/winner/Documents/workspace/project/src/main/java/"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaClientGenerator> <table tableName="table_name" domainObjectName="object_name" enableCountByExample= "false" enableUpdateByExample= "false" enableDeleteByExample= "false" enableSelectByExample= "false" selectByExampleQueryId= "false"/> </context> </generatorConfiguration>
然后定位到pom.xml所在的路径下面,运行:
mvn mybatis-generator:generate
所有的文件就会自动生成,怎一个爽字了得。
(四)Maven命令
常用命令
从某种意义上来说,软件是帮助不懂程序的人来操作计算机的,图形化界面尤其如此。在上个世纪,比尔盖茨之所以成为世界首富,微软之所以IT界的巨鳄,就是因为Windows开图形化操作之先河,并抢先占领了全球市场,笑傲江湖数十年,至今依然宝刀未老。
诚然,现在几乎每种软件都有图形化界面,用鼠标点击几下就可以完成操作。Maven也不例外,在各类IDE中都有成熟的插件来简化操作。
但是作为开发人员,应该时刻保持着一种职业神圣感,我们拥有上帝之手,借助程序来操纵着计算机世界的一切。我们与计算机交流的正途是通过命令,而不是图形化界面。东汉末年分三国,为什么?很大一部分因素就是因为宦官集团隔断了皇权与士大夫之间的直接联系!图形化界面是人机交互的第三者,阻止着我们与计算机的亲密接触,长此以往,必生间隙。吾辈不可不慎也哉!
总而言之,图形化界面不是不能用,因为它确实有好处,可以提高开发效率,规避操作失误。我的观点是,用它,但是不要依赖它。
作为开发利器的maven,为我们提供了十分丰富的命令,了解maven的命令行操作并熟练运用常见的maven命令还是十分必要的。无论多先进多炫的图形化界面,底层都得靠maven命令来驱动。知其然,知其所以然,方能百战不殆。
在讲解插件的那一篇文章中已经说过,maven的所有任务都是通过插件来完成的,它本身只是一个空空如也的框架,不具备执行具体任务的能力。
maven的命令格式如下:
mvn [plugin-name]:[goal-name]
该命令的意思是:执行“plugin-name”插件的“goal-name”目标(或者称为动作)。
用户可以通过两种方式调用Maven插件目标。第一种方式是将插件目标与生命周期阶段(lifecycle phase)绑定,这样用户在命令行只是输入生命周期阶段而已,例如Maven默认将maven-compiler-plugin的compile目标与compile生命周期阶段绑定,因此命令mvn compile实际上是先定位到compile这一生命周期阶段,然后再根据绑定关系调用maven-compiler-plugin的compile目标。第二种方式是直接在命令行指定要执行的插件目标,例如mvnarchetype:generate 就表示调用maven-archetype-plugin的generate目标,这种带冒号的调用方式与生命周期无关。
常用的maven命令如下:
Maven命令列表
mvn –version
显示版本信息
mvn clean
清理项目生产的临时文件,一般是模块下的target目录
mvn compile
编译源代码,一般编译模块下的src/main/java目录
mvn package
项目打包工具,会在模块下的target目录生成jar或war等文件
mvn test
测试命令,或执行src/test/java/下junit的测试用例.
mvn install
将打包的jar/war文件复制到你的本地仓库中,供其他模块使用
mvn deploy
将打包的文件发布到远程参考,提供其他人员进行下载依赖
mvn site
生成项目相关信息的网站
mvn eclipse:eclipse
将项目转化为Eclipse项目
mvn dependency:tree
打印出项目的整个依赖树
mvn archetype:generate
创建Maven的普通java项目
mvn tomcat:run
在tomcat容器中运行web应用
mvn jetty:run
调用 Jetty 插件的 Run 目标在 Jetty Servlet 容器中启动 web 应用
注意:运行maven命令的时候,首先需要定位到maven项目的目录,也就是项目的pom.xml文件所在的目录。否则,必以通过参数来指定项目的目录。
命令参数
上面列举的只是比较通用的命令,其实很多命令都可以携带参数以执行更精准的任务。
Maven命令可携带的参数类型如下:
1. -D 传入属性参数
比如命令:
mvn package -Dmaven.test.skip=true
以“-D”开头,将“maven.test.skip”的值设为“true”,就是告诉maven打包的时候跳过单元测试。同理,“mvn deploy-Dmaven.test.skip=true”代表部署项目并跳过单元测试。
2. -P 使用指定的Profile配置
比如项目开发需要有多个环境,一般为开发,测试,预发,正式4个环境,在pom.xml中的配置如下:
<profiles> <profile> <id>dev </id> <properties> <env>dev </env> </properties> <activation> <activeByDefault>true </activeByDefault> </activation> </profile> <profile> <id>qa </id> <properties> <env>qa </env> </properties> </profile> <profile> <id>pre </id> <properties> <env>pre </env> </properties> </profile> <profile> <id>prod </id> <properties> <env>prod </env> </properties> </profile> </profiles> ...... <build> <filters> <filter>config/${env}.properties </filter> </filters> <resources> <resource> <directory>src/main/resources </directory> <filtering>true </filtering> </resource> </resources> ...... </build>
profiles定义了各个环境的变量id,filters中定义了变量配置文件的地址,其中地址中的环境变量就是上面profile中定义的值,resources中是定义哪些目录下的文件会被配置文件中定义的变量替换。
通过maven可以实现按不同环境进行打包部署,命令为:
mvn package -P dev
其中“dev“为环境的变量id,代表使用Id为“dev”的profile。
3. -e 显示maven运行出错的信息
4. -o 离线执行命令,即不去远程仓库更新包
5. -X 显示maven允许的debug信息
6. -U 强制去远程更新snapshot的插件或依赖,默认每天只更新一次
maven命令实例
下面结合几个实例来看看maven命令的使用方法。
archetype:create & archetype:generate
“archetype”是“原型”的意思,maven可以根据各种原型来快速创建一个maven项目。
archetype:create是maven 3.0.5之前创建项目的命令,例如创建一个普通的Java项目:
mvn archetype:create -DgroupId=packageName -DartifactId=projectName -Dversion=1.0.0-SNAPSHOT
后面的三个参数用于指定项目的groupId、artifactId以及version。
创建Maven的Web项目:
mvnarchetype:create -DgroupId=packageName -DartifactId=projectName -DarchetypeArtifactId=maven-archetype-webapp
archetypeArtifactId参数用于指定使用哪个maven原型,这里使用的是maven-archetype-webapp,maven会按照web应用的目录结构生成项目。
需要注意的是,在maven 3.0.5之后,archetype:create命令不在使用,取而代之的是archetype:generate命令。
该命令会以交互的模式创建maven项目,不需要像archetype:create那样在后面跟一堆参数,很容易出错。
但是,在命令行直接运行archetype:generat,往往会出现下面的结果:
程序卡在了“Generatingproject in Interactive mode”这一步,加入“-X”参数显示详细信息:
mvn -X archetype:generate
运行结果如下:
可见,最终是卡到这一行,maven默认会从远程服务器上获取catalog,archetypeCatalog 表示插件使用的archetype元数据,默认值为remote,local,即中央仓库archetype元数据 (http://repo1.maven.org/maven2/archetype-catalog.xml)加上插件内置元数据,由于中央仓库的archetype太多(几千个)而造成程序的阻滞。实际上我们使用不了那么多的原型,加入-DarchetypeCatalog=internal参数就可以避免这种情况,只使用内置的原型就够了:
mvn archetype:generate -DarchetypeCatalog=internal
然后maven会告诉你,archetype没有指定,默认使用maven-archetype-quickstart,或者你从下面的列表中选择一个可用的原型:
列表中可用的内置原型共有10个,我们选择使用maven-archetype-quickstart原型(相当于一个“HelloWorld”模板)来创建项目,输入对应的序号“7”即可。
然后会依次提醒你输入groupId、artifactId、version(默认1.0-SNAPSHOT)以及创建的第一个包名。
如果构建成功就会在你的当前目录下,按照你输入的参数生成一个maven项目。
eclipse:eclipse
正式的开发环境中,代码一般是通过cvs、svn或者git来管理,我们从服务器下载下来源代码,然后执行mvn eclipse:eclipse生成ecllipse项目文件,然后导入到eclipse就行了。
tomcat:run
用了maven后,可以不需要用eclipse里的tomcat来运行web项目(实际工作中经常会发现用它会出现不同步更新的情况),只需在对应目录里运行 mvn tomat:run命令,然后就可在浏览器里运行查看了。
首先来看一下maventomcat插件的配置:
然后配置jsp,servlet依赖等:
<plugin> <groupId>org.apache.tomcat.maven </groupId> <artifactId>tomcat7-maven-plugin </artifactId> <version>2.2 </version> <configuration> <port>8080 </port> <path>/dubbo-admin </path> <uriEncoding>UTF-8 </uriEncoding> <finalName>dubbo-admin </finalName> <server>tomcat7 </server> </configuration> </plugin>
<dependency> <groupId>javax.servlet </groupId> <artifactId>servlet-api </artifactId> <version>2.5 </version> <scope>provided </scope> </dependency> <dependency> <groupId>javax.servlet.jsp </groupId> <artifactId>jsp-api </artifactId> <version>2.2 </version> <scope>provided </scope> </dependency> <dependency> <groupId>javax.servlet </groupId> <artifactId>jstl </artifactId> <version>1.2 </version> </dependency> <dependency> <groupId>jsptags </groupId> <artifactId>pager-taglib </artifactId> <version>2.0 </version> <scope>provided </scope> </dependency>然后按照下面的方式运行:
还可以加入以下参数:跳过测试:-Dmaven.test.skip(=true);指定端口:-Dmaven.tomcat.port=9090;忽略测试失败:-Dmaven.test.failure.ignore=true当然,如果你的其它关联项目有过更新的话,一定要在项目根目录下运行mvn clean install来执行更新,再运行mvn tomcat:run使改动生效。
help:describe
maven有各种插件,插件又有各种目标。我们不可能记得每个插件命令。maven提供了查询各类插件参数的命令:mvn help:describe。
例如:mvn help:describe -Dplugin=help
代表查询help 插件的命令规范,然后maven就会告诉你该命令有几个goal,各种参数的的意义以及配置方法:
下面的命令则代表插叙该插件的详细命令参数:
mvn help:describe -Dplugin=help -Dfull
maven会告诉你该命令有什么参数,怎么使用,一览无余。
(五)Maven仓库
本地仓库
Maven一个很突出的功能就是jar包管理,一旦工程需要依赖哪些jar包,只需要在Maven的pom.xml配置一下,该jar包就会自动引入工程目录。初次听来会觉得很神奇,下面我们来探究一下它的实现原理。
首先,这些jar包肯定不是没爹没娘的孩子,它们有来处,也有去处。集中存储这些jar包(还有插件等)的地方被称之为仓库(Repository)。
不管这些jar包从哪里来的,必须存储在自己的电脑里之后,你的工程才能引用它们。类似于电脑里有个客栈,专门款待这些远道而来的客人,这个客栈就叫做本地仓库。
比如,工程中需要依赖spring-core这个jar包,在pom.xml中声明之后,maven会首先在本地仓库中找,如果找到了很好办,自动引入工程的依赖lib库即可。可是,万一找不到呢?实际上这种情况经常发生,尤其初次使用maven的时候,本地仓库肯定是空无一物的,这时候就要靠maven大展神通,去远程仓库去下载。
远程仓库
说到远程仓库,先从最核心的中央仓库开始,中央仓库是默认的远程仓库,maven在安装的时候,自带的默认中央仓库地址为http://repo1.maven.org/maven2/,此仓库由Maven社区管理,包含了绝大多数流行的开源Java构件,以及源码、作者信息、SCM、信息、许可证信息等。一般来说,简单的Java项目依赖的构件都可以在这里下载到。Maven社区提供了一个中央仓库的搜索地址:http://search.maven.org/#browse,可以查询到所有可用的库文件。
除了中央仓库,还有其它很多公共的远程仓库,如中央仓库的镜像仓库。全世界都从中央仓库请求资源,累死宝宝了,所以在世界各地还有很多中央仓库的镜像仓库。镜像仓库可以理解为仓库的副本,会从原仓库定期更新资源,以保持与原仓库的一致性。从仓库中可以找到的构件,从镜像仓库中也可以找到,直接访问镜像仓库,更快更稳定。
除此之外,还有很多各具特色的公共仓库,如果需要都可以在网上找到,比如Apache Snapshots仓库,包含了来自于Apache软件基金会的快照版本。
实际开发中,一般不会使用maven默认的中央仓库,现在业界使用最广泛的仓库地址为: http://mvnrepository.com/,比默认的中央仓库更快、更全、更稳定,谁用谁知道。
下面就是spring-core的最新版本在该仓库的信息:
一般来讲,公司都会通过自己的私有服务器在局域网内架设一个仓库代理。私服可以看作一种特殊的远程仓库,代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,先从私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。
Maven私服有很多好处:
1.可以把公司的私有jar包,以及无法从外部仓库下载到的构件上传到私服上,供公司内部使用;
2.节省自己的外网带宽:减少重复请求造成的外网带宽消耗;
2.加速Maven构建:如果项目配置了很多外部远程仓库的时候,构建速度就会大大降低;
4.提高稳定性,增强控制:Internet不稳定的时候,maven构建也会变的不稳定,一些私服软件还提供了其他的功能
当前主流的maven私服有Apache的Archiva、JFrog的Artifactory以及Sonatype的Nexus。
上面提到的中央仓库、中央仓库的镜像仓库、其他公共仓库、私服都属于远程仓库的范畴。
如果maven没有在本地仓库找到想要的东西,就会自动去配置文件中指定的远程仓库寻找,找到后将它下载到你的本地仓库。如果连远程仓库都找不到想要的东西,maven很生气,累老子跑了一圈都没找到,肯定是你配置写错了,报错给你看。
仓库的配置
仓库配置要做两件事,一是告诉maven你的本地仓库在哪里,二是你的远程仓库在哪里。
顾名思义,setting.xml的第一个节点<localRepository>就是配置本地仓库的地方,不用赘言。
远程仓库的配置有些复杂,因为会涉及很多附属特性。下面以一切从实际出发,看看使用私服的情况下如何配置远程仓库。稍微像样的公司都会建立自己的私服,如果一个公司连自己的私服都没有(别管是因为买不起服务器还是技术上做不到),你可以考虑一下跳槽的问题了。
现在最流行的maven仓库管理器就是大名鼎鼎的Nexus(发音[ˈnɛksəs],英文中代表“中心、魔枢”的意思),它极大地简化了自己内部仓库的维护和外部仓库的访问。利用Nexus可以只在一个地方就能够完全控制访问和部署在你所维护仓库中的每个Artifact。Nexus是一套“开箱即用”的系统不需要数据库,它使用文件系统加Lucene来组织数据。
至于Nexus怎么部署,怎么维护仓库,作为开发人员是不需要关心的,只需要把Nexus私服的局域网地址写入maven的本地配置文件即可。具体的配置方法如下:
1、设置镜像
-
<mirrors>
-
<mirror>
-
<!--该镜像的唯一标识符。id用来区分不同的mirror元素。 -->
-
<id>nexus </id>
-
<!-- 镜像名,起注解作用,应做到见文知意。可以不配置 -->
-
<name>Human Readable Name </name>
-
<!-- 所有仓库的构件都要从镜像下载 -->
-
<mirrorOf>* </mirrorOf>
-
<!-- 私服的局域网地址-->
-
<url>http://192.168.0.1:8081/nexus/content/groups/public/ </url>
-
</mirror>
-
</mirrors>
节点<mirrors>下面可以配置多个镜像,<mirrorOf>用于指明是哪个仓库的镜像,上例中使用通配符“*”表明该私服是所有仓库的镜像,不管本地使用了多少种远程仓库,需要下载构件时都会从私服请求。
如果只想将私服设置成某一个远程仓库的镜像,使用<mirrorOf>指定该远程仓库的ID即可。
2、设置远程仓库
远程仓库的设置是在<profile>节点下面:
-
<repositories>
-
<repository>
-
-
<!--仓库唯一标识 -->
-
<id>repoId </id>
-
-
<!--远程仓库名称 -->
-
<name>repoName </name>
-
-
<!--远程仓库URL,如果该仓库配置了镜像,这里的URL就没有意义了,因为任何下载请求都会交由镜像仓库处理,前提是镜像(也就是设置好的私服)需要确保该远程仓库里的任何构件都能通过它下载到 -->
-
<url>http://…… </url>
-
-
<!--如何处理远程仓库里发布版本的下载 -->
-
<releases>
-
-
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
-
<enabled>false </enabled>
-
-
<!-- 该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:-->
-
<!-- always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。 -->
-
<updatePolicy>always </updatePolicy>
-
-
<!--当Maven验证构件校验文件失败时该怎么做:-->
-
<!--ignore(忽略),fail(失败),或者warn(警告)。 -->
-
<checksumPolicy>warn </checksumPolicy>
-
-
</releases>
-
-
<!--如何处理远程仓库里快照版本的下载,与发布版的配置类似 -->
-
<snapshots>
-
<enabled/>
-
<updatePolicy/>
-
<checksumPolicy/>
-
</snapshots>
-
-
</repository>
-
</repositories>
可以配置多个远程仓库,用<id>加以区分。
除此之外,还有一个与<repositories>并列存在<pluginRepositories>节点,用来配置插件的远程仓库。
仓库主要存储两种构件。第一种构件被用作其它构件的依赖,最常见的就是各类jar包。这是中央仓库中存储的大部分构件类型。另外一种构件类型是插件,Maven插件是一种特殊类型的构件。由于这个原因,插件仓库独立于其它仓库。<pluginRepositories>节点与<repositories>节点除了根节点的名字不一样,子元素的结构与配置方法完全一样:
-
<pluginRepositories>
-
<pluginRepository>
-
-
<id />
-
<name />
-
<url />
-
-
<releases>
-
<enabled />
-
<updatePolicy />
-
<checksumPolicy />
-
</releases>
-
-
<snapshots>
-
<enabled />
-
<updatePolicy />
-
<checksumPolicy />
-
</snapshots>
-
-
</pluginRepository>
-
</pluginRepositories>
远程仓库有releases和snapshots两组配置,POM就可以在每个单独的仓库中,为每种类型的构件采取不同的策略。例如,有时候会只为开发目的开启对快照版本下载的支持,就需要把<releases>中的<enabled >设为“false”,而<snapshots>中的<enabled >设为“true”。
由于远程仓库的配置是挂在<profile>节点下面,如果配置有多个<profile>节点,那么就可能有多种远程仓库的设置方案,该方案是否生效是由它的父节点<profile>是否被激活决定的。
3、设置发布权限
私服的作用除了可以给全公司的人提供maven构件的下载,还有一个非常重要的功能,就是开发者之间的资源共享。
一个大的项目往往是分模块进行开发的,各个模块之间存在依赖关系,比如一个交易系统,分为下单模块、支付模块、购物车模块等。现在开发下单模块的同学需要调用支付模块中的接口来完成支付功能,就需要将支付模块的某些jar包引入本地工程,才能调用它的接口;同时,开发购物车模块的同学需要调用下单模块的接口,来完成下单功能,他就需要依赖下单模块的某些jar包。这三个模块都在持续开发中,不可能将各自的源码传来传去支持对方的依赖。
解决的方式是这样,每个模块完成了某个阶段性的功能,都会将提供对外服务的接口打成jar包,传到公司的私服当中,谁要使用该模块的功能,只需要在pom.xml文件中声明一下,maven就会像下载其他jar包那样把它引入你的工程。
在开发过程中,在pom中声明的构件版本一般是快照版:
-
<dependency>
-
<groupId>com.yourCompany.trade </groupId>
-
<artifactId>trade-pay </artifactId>
-
<version>1.0.2-SNAPSHOT </version>
-
</dependency>
各个模块会不断的上传新的jar包,如果本地项目依赖的是快照版,那么maven一旦发现该jar包有新的发布,就会将它下载下来替代以前的旧版本。比如,支付模块在测试的时候发现有个bug,修复了一下,然后将快照版发布到私服。而你只需要专注于下单模块的开发,所依赖的支付模块的更新由maven处理,不需要关心。一旦你开发的模块修复了一个bug,或者添加了一个新功能等修改,只需要将发布一次快照版本到私服即可,谁需要依赖你的接口谁自然会去私服下载,你也不用关心。
一般私服建立完毕之后不需要认证就可以访问,但是风险有多大,可以自己想象,比如有天女秘书不小心把她跟老板的艳照传到了私服,开发的同学就没心思干活了吧……所以私服的权限设置还是很有必要的。
这时就需要使用setting.xml中的servers元素了。需要注意的是,配置私服的信息是在pom文件中,但是认证信息则是在setting.xml中,这是因为pom文件往往是被提交到代码仓库中供所有成员访问的,而setting.xml是存放在本地的,这样是安全的。
在settings.xml中,配置具有发布发布版本和快照版本权限的用户:
上面的id是server的id,不是用户登陆的id,该id与distributionManagement中repository元素的id相匹配。maven是根据pom中的repository和distributionMnagement元素来找到匹配的发布地址:
注意:pom中的id必须与setting.xml中配置好的id一致。
然后运行maven cleandeploy命令,将自己开发的构件部署在私服上供组织内其他用户使用(maven clean deploy和maven clean install的区别:deploy是将该构件部署在私服中,而install是将构件存入自己的本地仓库中)。
在这里有人可能会有一个疑问,所有的仓库设置不是已经在setting.xml中配置好了吗,为什么在pom的发布管理节点当中还要配置一个url?
Setting.xml中配置的是你从哪里下载构件,而这里配置的是你要将构件发布到哪里。有时候可能下载用的仓库与上传用的仓库是两个地址,但是绝大多数情况下,两者都是由私服充当,就是说两者是同一个地址。
(六)setting.xml配置文件详解
setting.xml配置文件
maven的配置文件settings.xml存在于两个地方:
1.安装的地方:${M2_HOME}/conf/settings.xml
2.用户的目录:${user.home}/.m2/settings.xml
前者又被叫做全局配置,对操作系统的所有使用者生效;后者被称为用户配置,只对当前操作系统的使用者生效。如果两者都存在,它们的内容将被合并,并且用户范围的settings.xml会覆盖全局的settings.xml。
Maven安装后,用户目录下不会自动生成settings.xml,只有全局配置文件。如果需要创建用户范围的settings.xml,可以将安装路径下的settings复制到目录${user.home}/.m2/。Maven默认的settings.xml是一个包含了注释和例子的模板,可以快速的修改它来达到你的要求。
全局配置一旦更改,所有的用户都会受到影响,而且如果maven进行升级,所有的配置都会被清除,所以要提前复制和备份${M2_HOME}/conf/settings.xml文件,一般情况下不推荐配置全局的settings.xml。
-
"1.0" encoding="UTF-8" xml version=
-
-
<settings xmlns="http://maven.apache.org/POM/4.0.0"
-
xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
-
-
<!--本地仓库。该值表示构建系统本地仓库的路径。其默认值为${user.home}/.m2/repository。 -->
-
<localRepository>usr/local/maven </localRepository>
-
-
<!--Maven是否需要和用户交互以获得输入。如果Maven需要和用户交互以获得输入,则设置成true,反之则应为false。默认为true。 -->
-
<interactiveMode>true </interactiveMode>
-
-
<!--Maven是否需要使用plugin-registry.xml文件来管理插件版本。 -->
-
<!--如果设置为true,则在{user.home}/.m2下需要有一个plugin-registry.xml来对plugin的版本进行管理 -->
-
<!--默认为false。 -->
-
<usePluginRegistry>false </usePluginRegistry>
-
-
<!--表示Maven是否需要在离线模式下运行。如果构建系统需要在离线模式下运行,则为true,默认为false。 -->
-
<!--当由于网络设置原因或者安全因素,构建服务器不能连接远程仓库的时候,该配置就十分有用。 -->
-
<offline>false </offline>
-
-
<!--当插件的组织Id(groupId)没有显式提供时,供搜寻插件组织Id(groupId)的列表。 -->
-
<!--该元素包含一个pluginGroup元素列表,每个子元素包含了一个组织Id(groupId)。 -->
-
<!--当我们使用某个插件,并且没有在命令行为其提供组织Id(groupId)的时候,Maven就会使用该列表。 -->
-
<!--默认情况下该列表包含了org.apache.maven.plugins。 -->
-
<pluginGroups>
-
-
<!--plugin的组织Id(groupId) -->
-
<pluginGroup>org.codehaus.mojo </pluginGroup>
-
-
</pluginGroups>
-
-
<!--用来配置不同的代理,多代理profiles可以应对笔记本或移动设备的工作环境:通过简单的设置profile id就可以很容易的更换整个代理配置。 -->
-
<proxies>
-
-
<!--代理元素包含配置代理时需要的信息 -->
-
<proxy>
-
-
<!--代理的唯一定义符,用来区分不同的代理元素。 -->
-
<id>myproxy </id>
-
-
<!--该代理是否是激活的那个。true则激活代理。当我们声明了一组代理,而某个时候只需要激活一个代理的时候,该元素就可以派上用处。 -->
-
<active>true </active>
-
-
<!--代理的协议。 协议://主机名:端口,分隔成离散的元素以方便配置。 -->
-
<protocol>http://… </protocol>
-
-
<!--代理的主机名。协议://主机名:端口,分隔成离散的元素以方便配置。 -->
-
<host>proxy.somewhere.com </host>
-
-
<!--代理的端口。协议://主机名:端口,分隔成离散的元素以方便配置。 -->
-
<port>8080 </port>
-
-
<!--代理的用户名,用户名和密码表示代理服务器认证的登录名和密码。 -->
-
<username>proxyuser </username>
-
-
<!--代理的密码,用户名和密码表示代理服务器认证的登录名和密码。 -->
-
<password>somepassword </password>
-
-
<!--不该被代理的主机名列表。该列表的分隔符由代理服务器指定;例子中使用了竖线分隔符,使用逗号分隔也很常见。 -->
-
<nonProxyHosts>*.google.com|ibiblio.org </nonProxyHosts>
-
-
</proxy>
-
-
</proxies>
-
-
<!--配置服务端的一些设置。一些设置如安全证书不应该和pom.xml一起分发。这种类型的信息应该存在于构建服务器上的settings.xml文件中。 -->
-
<servers>
-
-
<!--服务器元素包含配置服务器时需要的信息 -->
-
<server>
-
-
<!--这是server的id(注意不是用户登陆的id),该id与distributionManagement中repository元素的id相匹配。 -->
-
<id>server001 </id>
-
-
<!--鉴权用户名。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。 -->
-
<username>my_login </username>
-
-
<!--鉴权密码 。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。 -->
-
<password>my_password </password>
-
-
<!--鉴权时使用的私钥位置。和前两个元素类似,私钥位置和私钥密码指定了一个私钥的路径(默认是/home/hudson/.ssh/id_dsa)以及如果需要的话,一个密钥 -->
-
<!--将来passphrase和password元素可能会被提取到外部,但目前它们必须在settings.xml文件以纯文本的形式声明。 -->
-
<privateKey>${usr.home}/.ssh/id_dsa </privateKey>
-
-
<!--鉴权时使用的私钥密码。 -->
-
<passphrase>some_passphrase </passphrase>
-
-
<!--文件被创建时的权限。如果在部署的时候会创建一个仓库文件或者目录,这时候就可以使用权限(permission)。-->
-
<!--这两个元素合法的值是一个三位数字,其对应了unix文件系统的权限,如664,或者775。 -->
-
<filePermissions>664 </filePermissions>
-
-
<!--目录被创建时的权限。 -->
-
<directoryPermissions>775 </directoryPermissions>
-
-
<!--传输层额外的配置项 -->
-
<configuration> </configuration>
-
-
</server>
-
-
</servers>
-
-
<!--为仓库列表配置的下载镜像列表。 -->
-
<mirrors>
-
-
<!--给定仓库的下载镜像。 -->
-
<mirror>
-
-
<!--该镜像的唯一标识符。id用来区分不同的mirror元素。 -->
-
<id>planetmirror.com </id>
-
-
<!--镜像名称 -->
-
<name>PlanetMirror Australia </name>
-
-
<!--该镜像的URL。构建系统会优先考虑使用该URL,而非使用默认的服务器URL。 -->
-
<url>http://downloads.planetmirror.com/pub/maven2 </url>
-
-
<!--被镜像的服务器的id。例如,如果我们要设置了一个Maven中央仓库(http://repo1.maven.org/maven2)的镜像,-->
-
<!--就需要将该元素设置成central。这必须和中央仓库的id central完全一致。 -->
-
<mirrorOf>central </mirrorOf>
-
-
</mirror>
-
-
</mirrors>
-
-
<!--根据环境参数来调整构建配置的列表。settings.xml中的profile元素是pom.xml中profile元素的裁剪版本。-->
-
<!--它包含了id,activation, repositories, pluginRepositories和 properties元素。-->
-
<!--这里的profile元素只包含这五个子元素是因为这里只关心构建系统这个整体(这正是settings.xml文件的角色定位),而非单独的项目对象模型设置。-->
-
<!--如果一个settings中的profile被激活,它的值会覆盖任何其它定义在POM中或者profile.xml中的带有相同id的profile。 -->
-
<profiles>
-
-
<!--根据环境参数来调整的构件的配置 -->
-
<profile>
-
-
<!--该配置的唯一标识符。 -->
-
<id>test </id>
-
-
<!--自动触发profile的条件逻辑。Activation是profile的开启钥匙。-->
-
<!--如POM中的profile一样,profile的力量来自于它能够在某些特定的环境中自动使用某些特定的值;这些环境通过activation元素指定。-->
-
<!--activation元素并不是激活profile的唯一方式。settings.xml文件中的activeProfile元素可以包含profile的id。-->
-
<!--profile也可以通过在命令行,使用-P标记和逗号分隔的列表来显式的激活(如,-P test)。 -->
-
<activation>
-
-
<!--profile默认是否激活的标识 -->
-
<activeByDefault>false </activeByDefault>
-
-
<!--activation有一个内建的java版本检测,如果检测到jdk版本与期待的一样,profile被激活。 -->
-
<jdk>1.7 </jdk>
-
-
<!--当匹配的操作系统属性被检测到,profile被激活。os元素可以定义一些操作系统相关的属性。 -->
-
<os>
-
-
<!--激活profile的操作系统的名字 -->
-
<name>Windows XP </name>
-
-
<!--激活profile的操作系统所属家族(如 'windows') -->
-
<family>Windows </family>
-
-
<!--激活profile的操作系统体系结构 -->
-
<arch>x86 </arch>
-
-
<!--激活profile的操作系统版本 -->
-
<version>5.1.2600 </version>
-
-
</os>
-
-
<!--如果Maven检测到某一个属性(其值可以在POM中通过${名称}引用),其拥有对应的名称和值,Profile就会被激活。-->
-
<!--如果值字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段 -->
-
<property>
-
-
<!--激活profile的属性的名称 -->
-
<name>mavenVersion </name>
-
-
<!--激活profile的属性的值 -->
-
<value>2.0.3 </value>
-
-
</property>
-
-
<!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。missing检查文件是否存在,如果不存在则激活profile。-->
-
<!--另一方面,exists则会检查文件是否存在,如果存在则激活profile。 -->
-
<file>
-
-
<!--如果指定的文件存在,则激活profile。 -->
-
<exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/ </exists>
-
-
<!--如果指定的文件不存在,则激活profile。 -->
-
<missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/ </missing>
-
-
</file>
-
-
</activation>
-
-
<!--对应profile的扩展属性列表。Maven属性和Ant中的属性一样,可以用来存放一些值。这些值可以在POM中的任何地方使用标记${X}来使用,这里X是指属性的名称。-->
-
<!--属性有五种不同的形式,并且都能在settings.xml文件中访问。 -->
-
<!--1. env.X: 在一个变量前加上"env."的前缀,会返回一个shell环境变量。例如,"env.PATH"指代了$path环境变量(在Windows上是%PATH%)。 -->
-
<!--2. project.x:指代了POM中对应的元素值。 -->
-
<!--3. settings.x: 指代了settings.xml中对应元素的值。 -->
-
<!--4. Java System Properties: 所有可通过java.lang.System.getProperties()访问的属性都能在POM中使用该形式访问, -->
-
<!-- 如/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0/jre。 -->
-
<!--5. x: 在<properties/>元素中,或者外部文件中设置,以${someVar}的形式使用。 -->
-
<properties>
-
-
<!-- 如果这个profile被激活,那么属性${user.install}就可以被访问了 -->
-
<user.install>usr/local/winner/jobs/maven-guide </user.install>
-
-
</properties>
-
-
<!--远程仓库列表,它是Maven用来填充构建系统本地仓库所使用的一组远程项目。 -->
-
<repositories>
-
-
<!--包含需要连接到远程仓库的信息 -->
-
<repository>
-
-
<!--远程仓库唯一标识 -->
-
<id>codehausSnapshots </id>
-
-
<!--远程仓库名称 -->
-
<name>Codehaus Snapshots </name>
-
-
<!--如何处理远程仓库里发布版本的下载 -->
-
<releases>
-
-
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
-
<enabled>false </enabled>
-
-
<!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:-->
-
<!--always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。 -->
-
<updatePolicy>always </updatePolicy>
-
-
<!--当Maven验证构件校验文件失败时该怎么做:-->
-
<!--ignore(忽略),fail(失败),或者warn(警告)。 -->
-
<checksumPolicy>warn </checksumPolicy>
-
-
</releases>
-
-
<!--如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置,POM就可以在每个单独的仓库中,为每种类型的构件采取不同的策略。-->
-
<!--例如,可能有人会决定只为开发目的开启对快照版本下载的支持。参见repositories/repository/releases元素 -->
-
<snapshots>
-
-
<enabled />
-
<updatePolicy />
-
<checksumPolicy />
-
-
</snapshots>
-
-
<!--远程仓库URL,按protocol://hostname/path形式 -->
-
<url>http://snapshots.maven.codehaus.org/maven2 </url>
-
-
<!--用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。-->
-
<!--Maven 2为其仓库提供了一个默认的布局;然而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。 -->
-
<layout>default </layout>
-
-
</repository>
-
-
</repositories>
-
-
<!--发现插件的远程仓库列表。仓库是两种主要构件的家。第一种构件被用作其它构件的依赖。这是中央仓库中存储的大部分构件类型。另外一种构件类型是插件。-->
-
<!--Maven插件是一种特殊类型的构件。由于这个原因,插件仓库独立于其它仓库。pluginRepositories元素的结构和repositories元素的结构类似。-->
-
<!--每个pluginRepository元素指定一个Maven可以用来寻找新插件的远程地址。 -->
-
<pluginRepositories>
-
-
<!--包含需要连接到远程插件仓库的信息.参见profiles/profile/repositories/repository元素的说明 -->
-
<pluginRepository>
-
<releases>
-
<enabled />
-
<updatePolicy />
-
<checksumPolicy />
-
</releases>
-
-
<snapshots>
-
<enabled />
-
<updatePolicy />
-
<checksumPolicy />
-
</snapshots>
-
-
<id />
-
<name />
-
<url />
-
<layout />
-
</pluginRepository>
-
-
</pluginRepositories>
-
-
<!--手动激活profiles的列表,按照profile被应用的顺序定义activeProfile。 该元素包含了一组activeProfile元素,每个activeProfile都含有一个profile id。-->
-
<!--任何在activeProfile中定义的profile id,不论环境设置如何,其对应的 profile都会被激活。-->
-
<!--如果没有匹配的profile,则什么都不会发生。例如,env-test是一个activeProfile,则在pom.xml(或者profile.xml)中对应id的profile会被激活。-->
-
<!--如果运行过程中找不到这样一个profile,Maven则会像往常一样运行。 -->
-
<activeProfiles>
-
-
<activeProfile>env-test </activeProfile>
-
-
</activeProfiles>
-
-
</profile>
-
-
</profiles>
-
-
</settings>
上面的配置文件对各个节点的含义及作用都有注解。实际应用中,经常使用的是<localRepository>、<servers>、<mirrors>、<profiles>有限几个节点,其他节点使用默认值足够应对大部分的应用场景。
<profile>节点
在仓库的配置一节中,已经对setting.xml中的常用节点做了详细的说明。在这里需要特别介绍一下的是<profile>节点的配置,profile是maven的一个重要特性。
<profile>节点包含了激活(activation),仓库(repositories),插件仓库(pluginRepositories)和属性(properties)共四个子元素元素。profile元素仅包含这四个元素是因为他们涉及到整个的构建系统,而不是个别的项目级别的POM配置。
profile可以让maven能够自动适应外部的环境变化,比如同一个项目,在linux下编译linux的版本,在win下编译win的版本等。一个项目可以设置多个profile,也可以在同一时间设置多个profile被激活(active)的。自动激活的 profile的条件可以是各种各样的设定条件,组合放置在activation节点中,也可以通过命令行直接指定。如果认为profile设置比较复杂,可以将所有的profiles内容移动到专门的 profiles.xml 文件中,不过记得和pom.xml放在一起。
activation节点是设置该profile在什么条件下会被激活,常见的条件有如下几个:
1. os
判断操作系统相关的参数,它包含如下可以自由组合的子节点元素
message - 规则失败之后显示的消息
arch - 匹配cpu结构,常见为x86
family - 匹配操作系统家族,常见的取值为:dos,mac,netware,os/2,unix,windows,win9x,os/400等
name - 匹配操作系统的名字
version - 匹配的操作系统版本号
display - 检测到操作系统之后显示的信息
2. jdk
检查jdk版本,可以用区间表示。
3. property
检查属性值,本节点可以包含name和value两个子节点。
4. file
检查文件相关内容,包含两个子节点:exists和missing,用于分别检查文件存在和不存在两种情况。
如果settings中的profile被激活,那么它的值将覆盖POM或者profiles.xml中的任何相等ID的profiles。
如果想要某个profile默认处于激活状态,可以在<activeProfiles>中将该profile的id放进去。这样,不论环境设置如何,其对应的 profile都会被激活。
(七)pom.xml配置文件详解
setting.xml主要用于配置maven的运行环境等一系列通用的属性,是全局级别的配置文件;而pom.xml主要描述了项目的maven坐标,依赖关系,开发者需要遵循的规则,缺陷管理系统,组织和licenses,以及其他所有的项目相关因素,是项目级别的配置文件。
基础配置
一个典型的pom.xml文件配置如下:
-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-
<!-- 模型版本。maven2.0必须是这样写,现在是maven2唯一支持的版本 -->
-
<modelVersion>4.0.0 </modelVersion>
-
-
<!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.winner.trade,maven会将该项目打成的jar包放本地路径:/com/winner/trade -->
-
<groupId>com.winner.trade </groupId>
-
-
<!-- 本项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
-
<artifactId>trade-core </artifactId>
-
-
<!-- 本项目目前所处的版本号 -->
-
<version>1.0.0-SNAPSHOT </version>
-
-
<!-- 打包的机制,如pom,jar, maven-plugin, ejb, war, ear, rar, par,默认为jar -->
-
<packaging>jar </packaging>
-
-
<!-- 帮助定义构件输出的一些附属构件,附属构件与主构件对应,有时候需要加上classifier才能唯一的确定该构件 不能直接定义项目的classifer,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的 -->
-
<classifier>... </classifier>
-
-
<!-- 定义本项目的依赖关系 -->
-
<dependencies>
-
-
<!-- 每个dependency都对应这一个jar包 -->
-
<dependency>
-
-
<!--一般情况下,maven是通过groupId、artifactId、version这三个元素值(俗称坐标)来检索该构件, 然后引入你的工程。如果别人想引用你现在开发的这个项目(前提是已开发完毕并发布到了远程仓库),-->
-
<!--就需要在他的pom文件中新建一个dependency节点,将本项目的groupId、artifactId、version写入, maven就会把你上传的jar包下载到他的本地 -->
-
<groupId>com.winner.trade </groupId>
-
<artifactId>trade-test </artifactId>
-
<version>1.0.0-SNAPSHOT </version>
-
-
<!-- maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。 -->
-
<!--scope包含如下的取值:compile(编译范围)、provided(已提供范围)、runtime(运行时范围)、test(测试范围)、system(系统范围) -->
-
<scope>test </scope>
-
-
<!-- 设置指依赖是否可选,默认为false,即子项目默认都继承:为true,则子项目必需显示的引入,与dependencyManagement里定义的依赖类似 -->
-
<optional>false </optional>
-
-
<!-- 屏蔽依赖关系。 比如项目中使用的libA依赖某个库的1.0版,libB依赖某个库的2.0版,现在想统一使用2.0版,就应该屏蔽掉对1.0版的依赖 -->
-
<exclusions>
-
<exclusion>
-
<groupId>org.slf4j </groupId>
-
<artifactId>slf4j-api </artifactId>
-
</exclusion>
-
</exclusions>
-
-
</dependency>
-
-
</dependencies>
-
-
<!-- 为pom定义一些常量,在pom中的其它地方可以直接引用 使用方式 如下 :${file.encoding} -->
-
<properties>
-
<file.encoding>UTF-8 </file.encoding>
-
<java.source.version>1.5 </java.source.version>
-
<java.target.version>1.5 </java.target.version>
-
</properties>
-
-
...
-
</project>
一般来说,上面的几个配置项对任何项目都是必不可少的,定义了项目的基本属性。
这里有必要对一个不太常用的属性classifier做一下解释,因为有时候引用某个jar包,classifier不写的话会报错。
classifier元素用来帮助定义构件输出的一些附属构件。附属构件与主构件对应,比如主构件是 kimi-app-2.0.0.jar,该项目可能还会通过使用一些插件生成 如kimi-app-2.0.0-javadoc.jar (Java文档)、 kimi-app-2.0.0-sources.jar(Java源代码) 这样两个附属构件。这时候,javadoc、sources就是这两个附属构件的classifier,这样附属构件也就拥有了自己唯一的坐标。
classifier的用途在于:
1. maven download javadoc / sources jar包的时候,需要借助classifier指明要下载那个附属构件
2. 引入依赖的时候,有时候仅凭groupId、artifactId、version无法唯一的确定某个构件,需要借助classifier来进一步明确目标。比如JSON-lib,有时候会同一个版本会提供多个jar包,在JDK1.5环境下是一套,在JDK1.3环境下是一套:
引用它的时候就要注明JDK版本,否则maven不知道你到底需要哪一套jar包:
-
<dependency>
-
<groupId>net.sf.json-lib </groupId>
-
<artifactId>json-lib </artifactId>
-
<version>2.4 </version>
-
<classifier>jdk15 </classifier>
-
</dependency>
构建配置
-
<build>
-
-
<!-- 产生的构件的文件名,默认值是${artifactId}-${version}。 -->
-
<finalName>myPorjectName </finalName>
-
-
<!-- 构建产生的所有文件存放的目录,默认为${basedir}/target,即项目根目录下的target -->
-
<directory>${basedir}/target </directory>
-
-
<!--当项目没有规定目标(Maven2叫做阶段(phase))时的默认值, -->
-
<!--必须跟命令行上的参数相同例如jar:jar,或者与某个阶段(phase)相同例如install、compile等 -->
-
<defaultGoal>install </defaultGoal>
-
-
<!--当filtering开关打开时,使用到的过滤器属性文件列表。 -->
-
<!--项目配置信息中诸如${spring.version}之类的占位符会被属性文件中的实际值替换掉 -->
-
<filters>
-
<filter>../filter.properties </filter>
-
</filters>
-
-
<!--项目相关的所有资源路径列表,例如和项目相关的配置文件、属性文件,这些资源被包含在最终的打包文件里。 -->
-
<resources>
-
<resource>
-
-
<!--描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。 -->
-
<!--举个例子,如果你想资源在特定的包里(org.apache.maven.messages),你就必须该元素设置为org/apache/maven/messages。 -->
-
<!--然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。 -->
-
<targetPath>resources </targetPath>
-
-
<!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性,文件在filters元素里列出。 -->
-
<filtering>true </filtering>
-
-
<!--描述存放资源的目录,该路径相对POM路径 -->
-
<directory>src/main/resources </directory>
-
-
<!--包含的模式列表 -->
-
<includes>
-
<include>**/*.properties </include>
-
<include>**/*.xml </include>
-
</includes>
-
-
<!--排除的模式列表 如果<include>与<exclude>划定的范围存在冲突,以<exclude>为准 -->
-
<excludes>
-
<exclude>jdbc.properties </exclude>
-
</excludes>
-
-
</resource>
-
</resources>
-
-
<!--单元测试相关的所有资源路径,配制方法与resources类似 -->
-
<testResources>
-
<testResource>
-
<targetPath />
-
<filtering />
-
<directory />
-
<includes />
-
<excludes />
-
</testResource>
-
</testResources>
-
-
<!--项目源码目录,当构建项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。 -->
-
<sourceDirectory>${basedir}\src\main\java </sourceDirectory>
-
-
<!--项目脚本源码目录,该目录和源码目录不同, <!-- 绝大多数情况下,该目录下的内容会被拷贝到输出目录(因为脚本是被解释的,而不是被编译的)。 -->
-
<scriptSourceDirectory>${basedir}\src\main\scripts
-
</scriptSourceDirectory>
-
-
<!--项目单元测试使用的源码目录,当测试项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。 -->
-
<testSourceDirectory>${basedir}\src\test\java </testSourceDirectory>
-
-
<!--被编译过的应用程序class文件存放的目录。 -->
-
<outputDirectory>${basedir}\target\classes </outputDirectory>
-
-
<!--被编译过的测试class文件存放的目录。 -->
-
<testOutputDirectory>${basedir}\target\test-classes
-
</testOutputDirectory>
-
-
<!--项目的一系列构建扩展,它们是一系列build过程中要使用的产品,会包含在running bulid‘s classpath里面。 -->
-
<!--他们可以开启extensions,也可以通过提供条件来激活plugins。 -->
-
<!--简单来讲,extensions是在build过程被激活的产品 -->
-
<extensions>
-
-
<!--例如,通常情况下,程序开发完成后部署到线上Linux服务器,可能需要经历打包、 -->
-
<!--将包文件传到服务器、SSH连上服务器、敲命令启动程序等一系列繁琐的步骤。 -->
-
<!--实际上这些步骤都可以通过Maven的一个插件 wagon-maven-plugin 来自动完成 -->
-
<!--下面的扩展插件wagon-ssh用于通过SSH的方式连接远程服务器, -->
-
<!--类似的还有支持ftp方式的wagon-ftp插件 -->
-
<extension>
-
<groupId>org.apache.maven.wagon </groupId>
-
<artifactId>wagon-ssh </artifactId>
-
<version>2.8 </version>
-
</extension>
-
-
</extensions>
-
-
<!--使用的插件列表 。 -->
-
<plugins>
-
<plugin>
-
<groupId> </groupId>
-
<artifactId>maven-assembly-plugin </artifactId>
-
<version>2.5.5 </version>
-
-
<!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。 -->
-
<executions>
-
<execution>
-
-
<!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标 -->
-
<id>assembly </id>
-
-
<!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段 -->
-
<phase>package </phase>
-
-
<!--配置的执行目标 -->
-
<goals>
-
<goal>single </goal>
-
</goals>
-
-
<!--配置是否被传播到子POM -->
-
<inherited>false </inherited>
-
-
</execution>
-
</executions>
-
-
<!--作为DOM对象的配置,配置项因插件而异 -->
-
<configuration>
-
<finalName>${finalName} </finalName>
-
<appendAssemblyId>false </appendAssemblyId>
-
<descriptor>assembly.xml </descriptor>
-
</configuration>
-
-
<!--是否从该插件下载Maven扩展(例如打包和类型处理器), -->
-
<!--由于性能原因,只有在真需要下载时,该元素才被设置成true。 -->
-
<extensions>false </extensions>
-
-
<!--项目引入插件所需要的额外依赖 -->
-
<dependencies>
-
<dependency>... </dependency>
-
</dependencies>
-
-
<!--任何配置是否被传播到子项目 -->
-
<inherited>true </inherited>
-
-
</plugin>
-
</plugins>
-
-
<!--主要定义插件的共同元素、扩展元素集合,类似于dependencyManagement, -->
-
<!--所有继承于此项目的子项目都能使用。该插件配置项直到被引用时才会被解析或绑定到生命周期。 -->
-
<!--给定插件的任何本地配置都会覆盖这里的配置 -->
-
<pluginManagement>
-
<plugins>... </plugins>
-
</pluginManagement>
-
-
</build>
pom里面的仓库与setting.xml里的仓库功能是一样的。主要的区别在于,pom里的仓库是个性化的。比如一家大公司里的setting文件是公用的,所有项目都用一个setting文件,但各个子项目却会引用不同的第三方库,所以就需要在pom里设置自己需要的仓库地址。
分发配置
-
<!--项目分发信息,在执行mvn deploy后表示要发布的位置。 -->
-
<!--有了这些信息就可以把网站部署到远程服务器或者把构件部署到远程仓库。 -->
-
<distributionManagement>
-
-
<!--部署项目产生的构件到远程仓库需要的信息 -->
-
<repository>
-
-
<!--是分配给快照一个唯一的版本号(由时间戳和构建流水号),还是每次都使用相同的版本号 -->
-
<!--参见repositories/repository元素 -->
-
<uniqueVersion>true </uniqueVersion>
-
-
<id> repo-id </id>
-
<name> repo-name </name>
-
<url>file://${basedir}/target/deploy </url>
-
<layout />
-
-
</repository>
-
-
<!--构件的快照部署到哪里,如果没有配置该元素,默认部署到repository元素配置的仓库 -->
-
<snapshotRepository>
-
<uniqueVersion />
-
<id />
-
<name />
-
<url />
-
<layout />
-
</snapshotRepository>
-
-
<!--部署项目的网站需要的信息 -->
-
<site>
-
-
<!--部署位置的唯一标识符,用来匹配站点和settings.xml文件里的配置 -->
-
<id> site-id </id>
-
-
<!--部署位置的名称 -->
-
<name> site-name </name>
-
-
<!--部署位置的URL,按protocol://hostname/path形式 -->
-
<url>scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web </url>
-
-
</site>
-
-
<!--项目下载页面的URL。如果没有该元素,用户应该参考主页。 -->
-
<!--使用该元素的原因是:帮助定位那些不在仓库里的构件(由于license限制)。 -->
-
<downloadUrl />
-
-
<!--如果构件有了新的groupID和artifact ID(构件移到了新的位置),这里列出构件的重定位信息。 -->
-
<relocation>
-
-
<!--构件新的group ID -->
-
<groupId />
-
-
<!--构件新的artifact ID -->
-
<artifactId />
-
-
<!--构件新的版本号 -->
-
<version />
-
-
<!--显示给用户的,关于移动的额外信息,例如原因。 -->
-
<message />
-
-
</relocation>
-
-
<!--给出该构件在远程仓库的状态。不得在本地项目中设置该元素,因为这是工具自动更新的。 -->
-
<!--有效的值有:none(默认),converted(仓库管理员从Maven 1 POM转换过来), -->
-
<!--partner(直接从伙伴Maven 2仓库同步过来),deployed(从Maven 2实例部署),verified(被核实时正确的和最终的)。 -->
-
<status />
-
-
</distributionManagement>
仓库配置
-
<!--发现依赖和扩展的远程仓库列表。 -->
-
<repositories>
-
-
<!--包含需要连接到远程仓库的信息 -->
-
<repository>
-
-
<!--如何处理远程仓库里发布版本的下载 -->
-
<releases>
-
-
<!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
-
<enabled />
-
-
<!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。 -->
-
<!--这里的选项是:always(一直),daily(默认,每日), -->
-
<!--interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。 -->
-
<updatePolicy />
-
-
<!--当Maven验证构件校验文件失败时该怎么做: -->
-
<!--ignore(忽略),fail(失败),或者warn(警告)。 -->
-
<checksumPolicy />
-
-
</releases>
-
-
<!--如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置, -->
-
<!--POM就可以在每个单独的仓库中,为每种类型的构件采取不同的策略。 -->
-
<!--例如,可能有人会决定只为开发目的开启对快照版本下载的支持 -->
-
<snapshots>
-
<enabled />
-
<updatePolicy />
-
<checksumPolicy />
-
</snapshots>
-
-
<!--远程仓库唯一标识符。可以用来匹配在settings.xml文件里配置的远程仓库 -->
-
<id> repo-id </id>
-
-
<!--远程仓库名称 -->
-
<name> repo-name </name>
-
-
<!--远程仓库URL,按protocol://hostname/path形式 -->
-
<url>http://192.168.1.169:9999/repository/ </url>
-
-
<!--用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。 -->
-
<!--Maven 2为其仓库提供了一个默认的布局; -->
-
<!--然而,Maven1.x有一种不同的布局。 -->
-
<!--我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。 -->
-
<layout> default </layout>
-
-
</repository>
-
-
</repositories>
-
-
<!--发现插件的远程仓库列表,这些插件用于构建和报表 -->
-
<pluginRepositories>
-
-
<!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素 -->
-
<pluginRepository />
-
-
</pluginRepositories>
profile配置
-
<!--在列的项目构建profile,如果被激活,会修改构建处理 -->
-
<profiles>
-
-
<!--根据环境参数或命令行参数激活某个构建处理 -->
-
<profile>
-
<!--自动触发profile的条件逻辑。Activation是profile的开启钥匙。 -->
-
<activation>
-
-
<!--profile默认是否激活的标识 -->
-
<activeByDefault>false </activeByDefault>
-
-
<!--activation有一个内建的java版本检测,如果检测到jdk版本与期待的一样,profile被激活。 -->
-
<jdk>1.7 </jdk>
-
-
<!--当匹配的操作系统属性被检测到,profile被激活。os元素可以定义一些操作系统相关的属性。 -->
-
<os>
-
-
<!--激活profile的操作系统的名字 -->
-
<name>Windows XP </name>
-
-
<!--激活profile的操作系统所属家族(如 'windows') -->
-
<family>Windows </family>
-
-
<!--激活profile的操作系统体系结构 -->
-
<arch>x86 </arch>
-
-
<!--激活profile的操作系统版本 -->
-
<version>5.1.2600 </version>
-
-
</os>
-
-
<!--如果Maven检测到某一个属性(其值可以在POM中通过${名称}引用),其拥有对应的名称和值,Profile就会被激活。 -->
-
<!-- 如果值字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段 -->
-
<property>
-
-
<!--激活profile的属性的名称 -->
-
<name>mavenVersion </name>
-
-
<!--激活profile的属性的值 -->
-
<value>2.0.3 </value>
-
-
</property>
-
-
<!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。missing检查文件是否存在,如果不存在则激活profile。 -->
-
<!--另一方面,exists则会检查文件是否存在,如果存在则激活profile。 -->
-
<file>
-
-
<!--如果指定的文件存在,则激活profile。 -->
-
<exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/ </exists>
-
-
<!--如果指定的文件不存在,则激活profile。 -->
-
<missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/ </missing>
-
-
</file>
-
-
</activation>
-
<id />
-
<build />
-
<modules />
-
<repositories />
-
<pluginRepositories />
-
<dependencies />
-
<reporting />
-
<dependencyManagement />
-
<distributionManagement />
-
<properties />
-
</profile>
pom.xml中的profile可以看做pom.xml的副本,拥有与pom.xml相同的子元素与配置方法。它包含可选的activation(profile的触发器)和一系列的changes。例如test过程可能会指向不同的数据库(相对最终的deployment)或者不同的dependencies或者不同的repositories,并且是根据不同的JDK来改变的。只需要其中一个成立就可以激活profile,如果第一个条件满足了,那么后面就不会在进行匹配。
报表配置
-
<!--描述使用报表插件产生报表的规范,特定的maven 插件能输出相应的定制和配置报表. -->
-
<!--当用户执行“mvn site”,这些报表就会运行,在页面导航栏能看到所有报表的链接。 -->
-
<reporting>
-
-
<!--true,则网站不包括默认的报表。这包括“项目信息”菜单中的报表。 -->
-
<excludeDefaults />
-
-
<!--所有产生的报表存放到哪里。默认值是${project.build.directory}/site。 -->
-
<outputDirectory />
-
-
<!--使用的报表插件和他们的配置。 -->
-
<plugins>
-
-
<plugin>
-
<groupId />
-
<artifactId />
-
<version />
-
<inherited />
-
<configuration>
-
<links>
-
<link>http://java.sun.com/j2se/1.5.0/docs/api/ </link>
-
</links>
-
</configuration>
-
<!--一组报表的多重规范,每个规范可能有不同的配置。 -->
-
<!--一个规范(报表集)对应一个执行目标 。例如,有1,2,3,4,5,6,7,8,9个报表。 -->
-
<!--1,2,5构成A报表集,对应一个执行目标。2,5,8构成B报表集,对应另一个执行目标 -->
-
<reportSets>
-
-
<!--表示报表的一个集合,以及产生该集合的配置 -->
-
<reportSet>
-
-
<!--报表集合的唯一标识符,POM继承时用到 -->
-
<id>sunlink </id>
-
-
<!--产生报表集合时,被使用的报表的配置 -->
-
<configuration />
-
-
<!--配置是否被继承到子POMs -->
-
<inherited />
-
-
<!--这个集合里使用到哪些报表 -->
-
<reports>
-
<report>javadoc </report>
-
</reports>
-
-
</reportSet>
-
-
</reportSets>
-
-
</plugin>
-
-
</plugins>
-
-
</reporting>
环境配置
-
<!--项目的问题管理系统(Bugzilla, Jira, Scarab,或任何你喜欢的问题管理系统)的名称和URL,本例为 jira -->
-
<issueManagement>
-
-
<!--问题管理系统(例如jira)的名字, -->
-
<system> jira </system>
-
-
<!--该项目使用的问题管理系统的URL -->
-
<url> http://jira.clf.com/ </url>
-
-
</issueManagement>
-
-
<!--项目持续集成信息 -->
-
<ciManagement>
-
-
<!--持续集成系统的名字,例如continuum -->
-
<system />
-
-
<!--该项目使用的持续集成系统的URL(如果持续集成系统有web接口的话)。 -->
-
<url />
-
-
<!--构建完成时,需要通知的开发者/用户的配置项。包括被通知者信息和通知条件(错误,失败,成功,警告) -->
-
<notifiers>
-
-
<!--配置一种方式,当构建中断时,以该方式通知用户/开发者 -->
-
<notifier>
-
-
<!--传送通知的途径 -->
-
<type />
-
-
<!--发生错误时是否通知 -->
-
<sendOnError />
-
-
<!--构建失败时是否通知 -->
-
<sendOnFailure />
-
-
<!--构建成功时是否通知 -->
-
<sendOnSuccess />
-
-
<!--发生警告时是否通知 -->
-
<sendOnWarning />
-
-
<!--不赞成使用。通知发送到哪里 -->
-
<address />
-
-
<!--扩展配置项 -->
-
<configuration />
-
-
</notifier>
-
-
</notifiers>
-
-
</ciManagement>
项目信息配置
-
<!--项目的名称, Maven产生的文档用 -->
-
<name>banseon-maven </name>
-
-
<!--项目主页的URL, Maven产生的文档用 -->
-
<url>http://www.clf.com/ </url>
-
-
<!--项目的详细描述, Maven 产生的文档用。 当这个元素能够用HTML格式描述时 -->
-
<!--(例如,CDATA中的文本会被解析器忽略,就可以包含HTML标签),不鼓励使用纯文本描述。 -->
-
<!-- 如果你需要修改产生的web站点的索引页面,你应该修改你自己的索引页文件,而不是调整这里的文档。 -->
-
<description>A maven project to study maven. </description>
-
-
<!--描述了这个项目构建环境中的前提条件。 -->
-
<prerequisites>
-
-
<!--构建该项目或使用该插件所需要的Maven的最低版本 -->
-
<maven />
-
-
</prerequisites>
-
-
<!--项目创建年份,4位数字。当产生版权信息时需要使用这个值。 -->
-
<inceptionYear />
-
-
<!--项目相关邮件列表信息 -->
-
<mailingLists>
-
-
<!--该元素描述了项目相关的所有邮件列表。自动产生的网站引用这些信息。 -->
-
<mailingList>
-
-
<!--邮件的名称 -->
-
<name> Demo </name>
-
-
<!--发送邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建 -->
-
-
-
<!--订阅邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建 -->
-
-
-
<!--取消订阅邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建 -->
-
-
-
<!--你可以浏览邮件信息的URL -->
-
<archive> http:/hi.clf.com/ </archive>
-
-
</mailingList>
-
-
</mailingLists>
-
-
<!--项目开发者列表 -->
-
<developers>
-
-
<!--某个项目开发者的信息 -->
-
<developer>
-
-
<!--SCM里项目开发者的唯一标识符 -->
-
<id> HELLO WORLD </id>
-
-
<!--项目开发者的全名 -->
-
<name> banseon </name>
-
-
<!--项目开发者的email -->
-
-
-
<!--项目开发者的主页的URL -->
-
<url />
-
-
<!--项目开发者在项目中扮演的角色,角色元素描述了各种角色 -->
-
<roles>
-
<role> Project Manager </role>
-
<role>Architect </role>
-
</roles>
-
-
<!--项目开发者所属组织 -->
-
<organization> demo </organization>
-
-
<!--项目开发者所属组织的URL -->
-
<organizationUrl>http://hi.clf.com/ </organizationUrl>
-
-
<!--项目开发者属性,如即时消息如何处理等 -->
-
<properties>
-
<dept> No </dept>
-
</properties>
-
-
<!--项目开发者所在时区, -11到12范围内的整数。 -->
-
<timezone> -5 </timezone>
-
-
</developer>
-
-
</developers>
-
-
<!--项目的其他贡献者列表 -->
-
<contributors>
-
-
<!--项目的其他贡献者。参见developers/developer元素 -->
-
<contributor>
-
<name />
-
<email />
-
<url />
-
<organization />
-
<organizationUrl />
-
<roles />
-
<timezone />
-
<properties />
-
</contributor>
-
-
</contributors>
-
-
<!--该元素描述了项目所有License列表。应该只列出该项目的license列表,不要列出依赖项目的license列表。 -->
-
<!--如果列出多个license,用户可以选择它们中的一个而不是接受所有license。 -->
-
<licenses>
-
-
<!--描述了项目的license,用于生成项目的web站点的license页面,其他一些报表和validation也会用到该元素。 -->
-
<license>
-
-
<!--license用于法律上的名称 -->
-
<name> Apache 2 </name>
-
-
<!--官方的license正文页面的URL -->
-
<url>http://www.clf.com/LICENSE-2.0.txt </url>
-
-
<!--项目分发的主要方式: repo,可以从Maven库下载 manual, 用户必须手动下载和安装依赖 -->
-
<distribution> repo </distribution>
-
-
<!--关于license的补充信息 -->
-
<comments> Abusiness-friendly OSS license </comments>
-
-
</license>
-
-
</licenses>
-
-
<!--SCM(Source Control Management)标签允许你配置你的代码库,供Maven web站点和其它插件使用。 -->
-
<scm>
-
-
<!--SCM的URL,该URL描述了版本库和如何连接到版本库。欲知详情,请看SCMs提供的URL格式和列表。该连接只读。 -->
-
<connection>scm:svn:http://svn.baidu.com/banseon/maven/ </connection>
-
-
<!--给开发者使用的,类似connection元素。即该连接不仅仅只读 -->
-
<developerConnection>scm:svn:http://svn.baidu.com/banseon/maven/
-
</developerConnection>
-
-
<!--当前代码的标签,在开发阶段默认为HEAD -->
-
<tag />
-
-
<!--指向项目的可浏览SCM库(例如ViewVC或者Fisheye)的URL。 -->
-
<url> http://svn.baidu.com/banseon </url>
-
-
</scm>
-
-
<!--描述项目所属组织的各种属性。Maven产生的文档用 -->
-
<organization>
-
-
<!--组织的全名 -->
-
<name> demo </name>
-
-
<!--组织主页的URL -->
-
<url> http://www.clf.com/ </url>
-
-
</organization>
(八)约定优于配置
maven的配置文件看似很复杂,其实只需要根据项目的实际背景,设置个别的几个配置项而已。maven有自己的一套默认配置,使用者除非必要,并不需要去修改那些约定内容。这就是所谓的“约定优于配置”。
文件目录
maven默认的文件存放结构如下:
每一个阶段的任务都知道怎么正确完成自己的工作,比如compile任务就知道从src/main/java下编译所有的java文件,并把它的输出class文件存放到target/classes中。
对maven来说,采用"约定优于配置"的策略可以减少修改配置的工作量,也可以降低学习成本,更重要的是,给项目引入了统一的规范。
版本规范
maven有自己的版本规范,一般是如下定义:
<majorversion>.<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"。各个部分的含义和处理逻辑如下说明:
l 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,也是从中拿出来的一个稳定版。
l LATEST
指某个特定构件的最新发布,这个发布可能是一个发布版,也可能是一个snapshot版,具体看哪个时间最后。
l RELEASE
指最后一个发布版。
Maven变量
除了在setting.xml以及pom.xml当中用properties定义的常量,maven还提供了一些隐式的变量,用来访问系统环境变量。
类别
例子
内置属性
${basedir}表示项目根目录,即包含pom.xml文件的目录
${version}表示项目版本
${project.basedir}同${basedir}
${project.baseUri}表示项目文件地址
${maven.build.timestamp}表示项目构件开始时间
setting属性
${settings.localRepository }表示本地仓库路径
POM属性
${project.build.directory}表示主源码路径
${project.build.sourceEncoding}表示主源码的编码格式
${project.build.sourceDirectory}表示主源码路径
${project.build.finalName}表示输出文件名称
${project.version}表示项目版本,与${version}相同
Java系统属性
${user.home}表示用户目录
${java.version}表示Java版本
环境变量属性
${env.JAVA_HOME}表示JAVA_HOME环境变量的值
${env.HOME }表示用户目录
上级工程变量
上级工程的pom中的变量用前缀 ${project.parent } 引用。上级工程的版本也可以这样引用: ${parent.version }
(九)依赖关系
在maven的管理体系中,各个项目组成了一个复杂的关系网,但是每个项目都是平等的,是个没有贵贱高低,众生平等的世界,全球每个项目从理论上来说都可以相互依赖。就是说,你跟开发Spring的大牛们平起平坐,你的项目可以依赖Spring项目,Spring项目也可以依赖你的项目(虽然现实中不太会发生,你倒贴钱人家也不敢引用)。
项目的依赖关系主要分为三种:依赖,继承,聚合
依赖关系
依赖关系是最常用的一种,就是你的项目需要依赖其他项目,比如Apache-common包,Spring包等等。
<dependency> <groupId>junit </groupId> <artifactId>junit </artifactId> <version>4.11 </version> <scope>test </scope> <type >jar </ type > <optional >true </ optional > </dependency>任意一个外部依赖说明包含如下几个要素: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]。
type 一般在pom引用依赖时候出现,其他时候不用。
maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。在maven中,scope包含如下的取值:
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仓库中引用依赖)。
dependency中的type一般不用配置,默认是jar。当type为pom时,代表引用关系:
<dependency> <groupId>org.sonatype.mavenbook </groupId> <artifactId>persistence-deps </artifactId> <version>1.0 </version> <type>pom </type> </dependency>此时,本项目会将persistence-deps的所有jar包导入依赖库。
可以创建一个打包方式为pom项目来将某些通用的依赖归在一起,供其他项目直接引用,不要忘了指定依赖类型为pom(<type>pom</type>)。
继承关系
继承就是避免重复,maven的继承也是这样,它还有一个好处就是让项目更加安全。项目之间存在上下级关系时就属于继承关系。
父项目的配置如下:
<project> <modelVersion>4.0.0 </modelVersion> <groupId>org.clf.parent </groupId> <artifactId>my-parent </artifactId> <version>2.0 </version> <packaging>pom </packaging> <!-- 该节点下的依赖会被子项目自动全部继承 --> <dependencies> <dependency> <groupId>org.slf4j </groupId> <artifactId>slf4j-api </artifactId> <version>1.7.7 </version> <type>jar </type> <scope>compile </scope> </dependency> </dependencies> <dependencyManagement> <!-- 该节点下的依赖关系只是为了统一版本号,不会被子项目自动继承,--> <!--除非子项目主动引用,好处是子项目可以不用写版本号 --> <dependencies> <dependency> <groupId>org.springframework </groupId> <artifactId>spring-orm </artifactId> <version>4.2.5.RELEASE </version> </dependency> <dependency> <groupId>org.springframework </groupId> <artifactId>spring-web </artifactId> <version>4.2.5.RELEASE </version> </dependency> <dependency> <groupId>org.springframework </groupId> <artifactId>spring-context-support </artifactId> <version>4.2.5.RELEASE </version> </dependency> <dependency> <groupId>org.springframework </groupId> <artifactId>spring-beans </artifactId> <version>4.2.5.RELEASE </version> </dependency> </dependencies> </dependencyManagement> <!-- 这个元素和dependencyManagement相类似,它是用来进行插件管理的--> <pluginManagement> ...... </pluginManagement> </project>注意,此时<packaging>必须为pom。
为了项目的正确运行,必须让所有的子项目使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布是相同的结果。
Maven 使用dependencyManagement 元素来提供了一种管理依赖版本号的方式。通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement 元素。使用pom.xml 中的dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。Maven 会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用在这个dependencyManagement 元素中指定的版本号。
父项目在dependencies声明的依赖,子项目会从全部自动地继承。而父项目在dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
如果某个项目需要继承该父项目,基础配置应该这样:
<project> <modelVersion>4.0.0 </modelVersion> <groupId>org.clf.parent.son </groupId> <artifactId>my-son </artifactId> <version>1.0 </version> <!-- 声明将父项目的坐标 --> <parent> <groupId>org.clf.parent </groupId> <artifactId>my-parent </artifactId> <version>2.0 </version> <!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。 --> <!-- 默认值是../pom.xml。Maven首先在构建当前项目的地方寻找父项目的pom, --> <!-- 其次在文件系统的这个位置(relativePath位置), --> <!-- 然后在本地仓库,最后在远程仓库寻找父项目的pom。 --> <relativePath>../parent-project/pom.xml </relativePath> </parent> <!-- 声明父项目dependencyManagement的依赖,不用写版本号 --> <dependencies> <dependency> <groupId>org.springframework </groupId> <artifactId>spring-web </artifactId> </dependency> <dependency> <groupId>org.springframework </groupId> <artifactId>spring-beans </artifactId> </dependency> </dependencies> </project>
聚合关系
随着技术的飞速发展和各类用户对软件的要求越来越高,软件本身也变得越来越复杂,然后软件设计人员开始采用各种方式进行开发,于是就有了我们的分层架构、分模块开发,来提高代码的清晰和重用。针对于这一特性,maven也给予了相应的配置。
maven的多模块管理也是非常强大的。一般来说,maven要求同一个工程的所有模块都放置到同一个目录下,每一个子目录代表一个模块,比如
总项目/
pom.xml 总项目的pom配置文件
子模块1/
pom.xml 子模块1的pom文件
子模块2/
pom.xml子模块2的pom文件
总项目的配置如下:
<project> <modelVersion>4.0.0 </modelVersion> <groupId>org.clf.parent </groupId> <artifactId>my-parent </artifactId> <version>2.0 </version> <!-- 打包类型必须为pom --> <packaging>pom </packaging> <!-- 声明了该项目的直接子模块 --> <modules> <!-- 这里配置的不是artifactId,而是这个模块的目录名称--> <module>module-1 </module> <module>module-2 </module> <module>module-3 </module> </modules> <!-- 聚合也属于父子关系,总项目中的dependencies与dependencyManagement、pluginManagement用法与继承关系类似 --> <dependencies> ...... </dependencies> <dependencyManagement> ...... </dependencyManagement> <pluginManagement> ...... </pluginManagement> </project>子模块的配置如下:
<project> <modelVersion>4.0.0 </modelVersion> <groupId>org.clf.parent.son </groupId> <artifactId>my-son </artifactId> <version>1.0 </version> <!-- 声明将父项目的坐标 --> <parent> <groupId>org.clf.parent </groupId> <artifactId>my-parent </artifactId> <version>2.0 </version> </parent> </project>
继承与聚合的关系
首先,继承与聚合都属于父子关系,并且,聚合 POM与继承关系中的父POM的packaging都是pom。
不同的是,对于聚合模块来说,它知道有哪些被聚合的模块,但那些被聚合的模块不知道这个聚合模块的存在。对于继承关系的父 POM来说,它不知道有哪些子模块继承与它,但那些子模块都必须知道自己的父 POM是什么。
在实际项目中,一个 POM往往既是聚合POM,又是父 POM,它继承了某个项目,本身包含几个子模块,同时肯定会存在普通的依赖关系,就是说,依赖、继承、聚合这三种关系是并存的。
Maven可继承的POM 元素列表如下:
groupId :项目组 ID ,项目坐标的核心元素;
version :项目版本,项目坐标的核心元素;
description :项目的描述信息;
organization :项目的组织信息;
inceptionYear :项目的创始年份;
url :项目的 url 地址
develoers :项目的开发者信息;
contributors :项目的贡献者信息;
distributionManagerment:项目的部署信息;
issueManagement :缺陷跟踪系统信息;
ciManagement :项目的持续继承信息;
scm :项目的版本控制信息;
mailingListserv :项目的邮件列表信息;
properties :自定义的 Maven 属性;
dependencies :项目的依赖配置;
dependencyManagement:醒目的依赖管理配置;
repositories :项目的仓库配置;
build :包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等;
reporting :包括项目的报告输出目录配置、报告插件配置等。