maven小试牛刀

      Maven是一个采用纯Java编写的开源项目管理工具。Maven采用了一种被称之为project object model (POM)概念来管理项目,全部的项目配置信息都被定义在一个叫作POM.xml的文件中,经过该文件,Maven能够管理项目的整个声明周期,包括编译,构建,测试,发布,报告等等。目前Apache下绝大多数项目都已经采用Maven进行管理。而Maven自己还支持多种插件,能够方便更灵活的控制项目。 java

 构建

        理解maven的第一步咱们须要知道构建是什么?《maven实战》这本书里写的很清楚,早上咱们会从代码库里签出最新的代码,而后进行单元测试,若是发现bug就会找同事一块儿解决,以后回到本身的工做上,编写单元测试或者产品代码,而后测试,午餐后可能会须要开个会,汇报工做进度,查看测试报告那么就须要用IDE使用相关的工具集成,生成报告给经理查看,也可能QA发来了几个bug,因而熟练地用IDE生成了一个WAR包,部署到Web容器下,启动容器。看到熟悉的界面了,遵循bug报告,一步步重现了bug。。。修改好bug,提交代码,通知QA,下班。就会发现,在一天的工做中,咱们出了编写代码就是在编译,运行生成文档,打包和部署等烦琐且不起眼的工做上,这就是构建。若是手工这样作,那成本也过高了,因而有人用软件的方法让这一系列工做彻底自动化,使得软件的构建能够像全自动流水线同样,只须要一条简单的命令,全部烦琐的步骤都可以自动完成,很快就能获得最终结果。程序员

       Maven的用途之一是服务于构建,它是一个异常强大的构建工具,可以帮咱们自动化构建过程,从清理、编译、测试到生成报告,再到打包和部署。咱们要作的是使用Maven配置好项目,而后输入简单的命令(如mvn clean install),Maven会帮咱们处理那些烦琐的任务。Maven是跨平台的,不管是在Windows上,仍是在Linux或者Mac上,均可以使用一样的命令。maven 能最大化的消除重复的构建,咱们不须要去定义繁琐的构建过程,只要在maven里配置好相关的信息就好。最简单的例子是测试,咱们不必告诉Maven去测试,更不须要告诉Maven如何运行测试,只须要遵循Maven的约定编写好测试用例,当咱们运行构建的时候,这些测试便会自动运行。maven能够帮助标准化构建过程,有了Maven以后,全部项目的构建命令都是简单一致的,这极大地避免了没必要要的学习成本,并且有利于促进项目团队的标准化。Maven做为一个构建工具,不只能帮咱们自动化构建,还可以抽象构建过程,提供构建任务实现;它跨平台,对外提供了一致的操做接口,这一切足以使它成为优秀的、流行的构建工具。web

       maven不只仅是一个构建工具,他仍是一个依赖管理工具和项目信息管理工具,它提供了中央仓库,能够帮咱们自动的下载构件。好比在使用javaweb开发是,会用到各类的第三方的库或者框架,这些类库均可以经过依赖的方式注入到项目中,随着依赖的增多,版本的不一致,版本的兼容性,臃肿的问题就会出现。每次手工的解决这些问题会很烦躁,maven就提供了一个优秀的解决方案,它经过一个坐标系统准确地定位每个构件(artifact),也就是经过一组坐标Maven可以找到任何一个Java类库(如jar文件)。Maven给这个类库世界引入了经纬,让它们变得有秩序,因而咱们能够借助它来有序地管理依赖,轻松地解决那些繁杂的依赖问题。算法

       Maven还能帮助咱们管理本来分散在项目中各个角落的项目信息,包括项目描述、开发者列表、版本控制系统地址、许可证、缺陷管理系统地址等。这些微小的变化看起来很琐碎,并不起眼,但却在不知不觉中为咱们节省了大量寻找信息的时间。除了直接的项目信息,经过Maven自动生成的站点,以及一些已有的插件,咱们还可以轻松得到项目文档、测试报告、静态分析报告、源码版本日志报告等很是具备价值的项目信息。spring

       maven与IDE的比较:apache

        IDE虽然提升了编码的效率,但编程

  • IDE依赖大量的手工操做。编译、测试、代码生成等工做都是相互独立的,很难一键完成全部工做。手工劳动每每意味着低效,意味着容易出错。设计模式

  • 很难在项目中统一全部的IDE配置,每一个人都有本身的喜爱。也正是因为这个缘由,一个在机器A上能够成功运行的任务,到了机器B的IDE中可能就会失败。api

        咱们应该合理利用IDE,而不是过多地依赖它。对于构建这样的任务,在IDE中一次次地点击鼠标是愚蠢的行为。Maven是这方面的专家,并且主流IDE都集成了Maven,咱们能够在IDE中方便地运行Maven执行构建。网络

        maven于ant的区别:

        ant意指“另外一个整洁的工具”(Another Neat Tool),它最先用来构建著名的Tomcat。能够将Ant当作是一个Java版本的Make,也正由于使用了Java,Ant是跨平台的。此外,Ant使用XML定义构建脚本build.xml。Ant是没有依赖管理的,因此很长一段时间Ant用户都不得不手工管理依赖,如今能够借助Ivy管理依赖。而Maven内置了依赖管理。

        使用maven的状况:

         好比你是一个小软件公司的程序员,他所在的公司要开发一个新的Web项目。通过协商,决定使用Spring、iBatis和Tapstry。jar包去哪里找呢?公司里估计没有人能把Spring、iBatis和Tapstry所使用的jar包一个很多地找出来。你们的作法是,先到Spring的站点上去找一个spring.with.dependencies,而后去iBatis的网站上把全部列出来的jar包下载下来,对Tapstry、Apache commons等执行一样的操做。项目尚未开始,WEB.INF/lib下已经有近百个jar包了,带版本号的、不带版本号的、有用的、没用的、相冲突的,怎一个“乱”字了得!  在项目开发过程当中,不时地会发现版本错误和版本冲突问题,这时只能硬着头皮逐一解决。项目开发到一半,经理发现最终部署的应用的体积实在太大了,要求去掉一些没用的jar包,因而只能加班加点地一个个删…… 这时就会想,要是能有一个系统或者框架来管理这些依赖就行了,  这时maven就发挥到做用了。

        书籍看到这里,让我想起大四的时候进来实验室时的一个项目,就是基于SSH框架的某公司管理系统,当时,在搭建环境的时候就须要一天的时候(网络卡),到不一样的网站去下不一样的jar包,和安装不一样的框架,期间出错了几回,为了不在次出错本身就手动的备份了全部资料,单独列了一个清单,记录各个依赖的版本。如今回过头来看,若是当时师兄师姐使用这个来构建项目的话,会有多轻松啊。实验室所学到的东西确实是有限的,不少新技术没有跟不上社会的变化。

        maven与极限编程:

        maven能很好的使用极限编程XP的一些实践当中去

  • 测试驱动开发(TDD)。TDD强调测试先行,全部产品都应该由测试用例覆盖。而测试是Maven生命周期的最重要的组成部分之一,而且Maven有现成的成熟插件支持业界流行的测试框架,如JUnit和TestNG。

  • 十分钟构建。十分钟构建强调咱们可以随时快速地从源码构建出最终的产品。这正是Maven所擅长的,只须要一些配置,以后用一条简单的命令就能让Maven帮你清理、编译、测试、打包、部署,而后获得最终的产品。

  • 持续集成(CI)。CI强调项目以很短的周期(如15分钟)集成最新的代码。实际上,CI的前提是源码管理系统和构建系统。

        在传统的瀑布模型开发中,项目依次要经历需求开发、分析、设计、编码、测试和集成发布阶段。从设计和编码阶段开始,就可使用Maven来创建项目的构建系统。在设计阶段,也彻底能够针对设计开发测试用例,而后再编写代码来知足这些测试用例。然而,有了自动化构建系统,咱们能够节省不少手动的测试时间。此外,尽早地使用构建系统集成团队的代码,对项目也是百利而无一害。最后,Maven还能帮助咱们快速地发布项目。

        maven安装:

        最新的eclipse中集成的是3.2.1的maven,为了和命令行一块儿使用,我在插件里面使用3.2.5的,本机上安装的也是3.2.5,这个只要在eclipse里面设置一下就行了。固然也能够设置回去的。

maven使用

 (一) 生成pom

        pom.xml 文件是maven对一个项目的核心配置,这个文件将包含你但愿如何构建项目的大多数配置信息,用于描述项目如何构建,声明项目依赖,等等。

        虽然很难列出一张很是全面的表,但在此可先列出最普通的默认的生命周期阶段:

  validate:验证工程是否正确,全部须要的资源是否可用。 
  compile:编译项目的源代码。   
  test:使用合适的单元测试框架来测试已编译的源代码。这些测试不须要已打包和布署。 
  Package:把已编译的代码打包成可发布的格式,好比jar。 
  integration-test:若有须要,将包处理和发布到一个可以进行集成测试的环境。 
  verify:运行全部检查,验证包是否有效且达到质量标准。 
  install:把包安装在本地的repository中,能够被其余工程做为依赖来使用。 
  Deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的repository,使得其余的开发者或者工程能够共享。 
  clean:清除先前构建的artifacts(在maven中,把由项目生成的包都叫做artifact)。 
  site:为项目生成文档站点。

  首先建立一个空文件夹,在改文件夹里新建一个文佳pom.xml,配置文件,具体内容为:

 

<span style="font-size: small;"><?xml version="1.0" encoding="UTF-8"?> 
<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.0 
http://maven.apache.org/maven-v4_0_0.xsd"> 
  <modelVersion>4.0.0</modelVersion> 
  <groupId>com.silence</groupId> 
  <artifactId>hello-world</artifactId> 
  <version>1.0-SNAPSHOT</version> 
  <name>Maven Hello World Project</name> 
</project>  
</span>

  第二行:project元素,这是pom.xml的根元素,声明pom相关的命名空间,这里面的属性可让咱们的IDE跟快速的编辑pom第一行:制定了该xml文档的版本和编码方式。

  第六行:根元素下的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven2及Maven 3来讲,它只能是4.0.0。

  第7行到9行是最重要的代码段,groupId,artifactId和version这三个元素定义了一个项目基本的坐标,在Maven的世界,任何的jar、pom或者war都是以基于这些基本的坐标进行区分的。

  groupId定义了项目属于哪一个组,这个组每每和项目所在的组织或公司存在关联,譬如你在googlecode上创建了一个名为myapp的项目,那么groupId就应该是com.googlecode.myapp,若是你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp。

  artifactId定义了当前Maven项目在组中惟一的ID,咱们为这个Hello World项目定义artifactId为hello-world,本书其余章节代码会被分配其余的artifactId。而在前面的groupId为com.googlecode.myapp的例子中,你可能会为不一样的子项目(模块)分配artifactId,如:myapp-util、myapp-domain、myapp-web等等。

  version指定了Hello World项目当前的版本——1.0-SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version会不断更新,如升级为1.0、1.1-SNAPSHOT、1.一、2.0等等。

  第十行:name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但我仍是推荐为每一个POM声明name,以方便信息交流。

(二)编写主代码

        项目主代码和测试代码不一样,项目的主代码会被打包到最终的构件中(好比jar),而测试代码只在运行测试时用到,不会被打包。默认状况下,Maven假设项目主代码位于src/main/java目录,咱们遵循Maven的约定,建立该目录,而后在该目录下建立文件com/juvenxu/mvnbook/helloworld/HelloWorld.java

       写好这个以后,能够回到项目根目录下,运行mvn clean compile就能够生成编译java文件,生成对应的class文件

(三)测试代码

        Maven项目中默认的测试代码目录是src/test/java。com/juvenxu/mvnbook/helloworld/testHelloWorld.java

  要有测试代码得为Hello World项目添加一个JUnit依赖,即在pom.xml中添加<dependencies>元素;

<dependencies> 
    <dependency> 
       <groupId>junit</groupId> 
       <artifactId>junit</artifactId> 
       <version>4.7</version> 
       <scope>test</scope> 
    </dependency> 
  </dependencies>

  

  第6行:scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效,换句话说,测试代码中的import JUnit代码是没有问题的,可是若是咱们在主代码中用import JUnit代码,就会形成编译错误。若是不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。有了这段声明,Maven就可以自动从中央仓库(http://repo1.maven.org/maven2/)里下载junit-4.7.jar。

(四)执行

  mvn clean compile、mvn clean test(测试)、mvn clean package(打包)、mvn clean install(安装)。执行test以前是会先执行compile的,执行package以前是会先执行test的,而相似地,install以前会执行package。

     命令行输入的是mvn clean test,而maven实际执行的可不止这两个任务,还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暂时咱们须要了解的是,在Maven执行测试(test)以前,它会先自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工做,这是Maven生命周期的一个特性。

(五)简单的原型Archetype

        能够快速的生成项目骨架,避免每次都一个个的建立文件夹,能够执行mvn archetype:generate,也能够在eclipse中选择。固然也能够根据本身的须要开发使用自定义的archetype来快速生成项目骨架。

maven坐标:

         为了能自动的解析任何一个java构件,maven就将他们用坐标惟一标识,坐标元素包括:groupId,artifactId,version,packaging,

classifier,只要设置这几个元素就能够很轻松地从中央仓库那儿得到对应的构件。前三天上面有介绍过,这里说说packaging:定义maven的打包方式,通常为jar(默认),固然也能够是war行的,最终会生成war的文件。classifier:帮助定义构建输出的一些附属构件。如某项目的主构件是nexus-index-2.0.0.jar,可能还会有nexus-index-2.0.0-Javadoc.jar和nexus-index-2.0.0-sources.jar这样一些附属构件(java文档和源代码),这里javadoc和sources就是这两个附属构件的classifier,这样附属的构件也会有本身惟一的坐标。

maven依赖:

  每一个依赖包含的元素有:groupId、artifactId、version还有type:

  scope:依赖范围。用来控制依赖与这三种classpath的关系(编译classpath、运行classpath、测试classpath),若是没有指定依赖范围则默认使用compile,在编译、运行和测试的时候都须要用到该依赖。test则只对测试classpath有效,在编译主代码和运行项目的时候不会包含进去。runtime运行时的依赖,对测试运行有效,在编译主代码时无效。其实,还有provided和system两种。

  optional:标记依赖是否可选,好比项目A依赖于项目B,B依赖于X和Y(XY可选的),根基依赖传递性,XY会是A的传递性依赖,可是因为XY是可选的,那么依赖不会传递,XY对A不会有影响。也就是说XY只对B起做用,不会被传递,若是A中须要XY则须要显示的声明。这个并不推荐,最好的方式就是排除依赖。可使用maven命令分析依赖关系:mvn dependency:analyze

  exclusions:用来排除传递性依赖

       maven引人的传递性依赖机制。一方面大大简化和方便了依赖声明。另外一方面,大部分状况下咱们只须要关心项目的直接依赖是什么,而不用考虑这些直接依赖会引人什么传递性依赖。但有时候,当传递性依赖形成问题的时候,咱们就须要清楚地知道该传递性依赖是从哪条依赖路径引人的。这个能够之后遇到了在了解。

  依赖范围

  就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系,Maven有如下几种依赖范围:

  compile: 编译依赖范围。若是没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。

  test: 测试依赖范围。使用此依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将没法使用此类依赖。典型的例子就是JUnit,它只有在编译测试代码及运行测试的时候才须要。

  provided: 已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候须要该依赖,但在运行项目的时候,因为容器已经提供,就不须要Maven重复地引入一遍。

  runtime: 运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只须要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才须要实现上述接口的具体JDBC驱动。

  system: 系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围彻底一致。可是,使用system范围依赖时必须经过systemPath元素显式地指定依赖文件的路径。因为此类依赖不是经过Maven仓库解析的,并且每每与本机系统绑定,可能形成构建的不可移植,所以应该谨慎使用。systemPath元素能够引用环境变量

maven仓库:

        简单来讲就是,maven依赖构件存放的地方,全部的依赖构件都从仓库里下载,除了本地的项目依赖。maven有提供一个中央仓库,里面有各类开源的构件,可很方便的从上面得到。固然,这个仓库是远程的,也能够在本地设置一个私服,Nexus就是一个流行的开源maven仓库管理软件。如今我只须要使用仓库里的就能够了,不必去创建私服。此处略过。

maven生命周期和插件:

        maven的生命周期就是为了对全部的构建过程进行抽象和统一,从大量项目和构建工具中学习和反思,而后总结了一套高度完善的、易扩展的生命周期。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎全部构建步骤。也就是说,几乎全部项目的构建,都能映射到这样一个生命周期上。

        在maven的设计中,实际的任务(如编译源代码)都交由插件来完成。这种思想与设计模式中的模板方法很是类似。模板方法模式在父类中定义算法的总体结构,子类能够经过实现或者重写父类的方法来控制实际的行为,这样既保证了算法有足够的可扩展性,又可以严格控制算法的总体结构。

  这本书里写的很清楚:

public abstract class AbstractBuild{
    public void Build(){
        initialize();
        compile();
        test();
        packagee();
        integrate();
        deploy();
    }
    protected abstract void initialize();
    protected abstract void compile();
    protected abstract void test();
    protected abstract void packagee();
    protected abstract void integrate();
    protected abstract void deploy();
}

     生命周期抽象了构建的各个步骤,定义它们的次序,但没有提供具体实现,那么谁来实现这些步骤呢?不能有用户为了编译而写一堆代码。为测试又写一堆代码,那么就在重复发明轮子了?maven考虑了,所以设计插件机制。每一个构建步骤均可以绑定一个或者多个插件行为,而maven为大多数构建步骤编写并绑定了默认插件。插件完成具体的任务,是实现着。maven有自动绑定的插件,固然也能够自定义绑定,在pom中设置build plugins plugin属性。 

  maven有三套独立的生命周期:clean(清理项目)、default(构建项目)、site(创建项目站点)。每一个生命周期都有几个阶段,这些阶段是有顺序的,调用后面的阶段时,必须先调用前面的阶段。咱们从命令行执行maven命令就是在调用其生命周期阶段,好比:mvn clean:就是执行pre-clean和clean阶段。mvn test:执行default周期的validate、initialize……直到test阶段。mvn clean install:就是clean阶段加上default周期的直到install阶段。

maven聚合和继承:

        咱们一般会将不一个项目分红不一样的模块向,注册服务会分红persist,service等模块,maven的聚合特性可以把项日的各个模块聚合在一块儿构建,而maven继承特性则能帮助抽取各模块相同的依赖和插件等配置。在众多模块中,不可能对每一个项目都进行构建,执行maven命令,会想用一个命令就运行几个模块的内容,为了可以一条命令就构建两个模块,须要在额外的建立一个account-aggregato模块,而后经过该模块构建整个项目的全部模块。对于聚合模块来讲,pom.xml中的打包方式必须为pom,不然就没法构建。各个模块能够放在聚合模块目录下,即和pom同一个目录,聚合模块是项目目录的最顶层,其余莫快则做为其子目录存在。这个并非惟一的,子模块也能够和聚合模块平行。

       多模块项目中,各模块中会有不少相同的groupID和version,相同的spring依赖,和plugin配置。这就是重复,重复每每觉得着更

更多的劳动和更多的潜在的问题。在面向对象世界中,程序员可使用类继承在必定程度上消除重复,在maven的世界中,也有相似的机制能让咱们抽取出重复的配置,这就是POM的继承。须要建立POM的斧子结构,而后在父POM中声明一些配置供子POM继承。以实现一处声明,多处使用的目的。

       聚合的目的:快速构建项目

       继承的目的:消除重复配置

 

参考书籍:《maven实战》 http://hzbook.group.iteye.com/group/wiki/2872-Maven-in-action

相关文章
相关标签/搜索