Maven基础


http://blog.csdn.net/wang379275614/article/details/43938011



1.    何为Maven

  Maven 是一个跨平台的项目管理和构建自动化工具。但是对于我们程序员来说,我们最关心的是它的项目构建功能。

  Maven 是基于项目对象模型的(POM),这个单词来自于“意第绪语(一种犹太人语言)”,意为“知识的积累”。作为Apache组织中一个颇为成功的开源项目,Maven主要服务于基于Java平台的项目构建依赖管理项目信息管理


2.    何为构建(build)

       通常我们将从拿到源码到得到最终的产品的过程(源码-->产品)叫过“构建”。这个过程一般包括编译、测试、生成文档、打包、部署等等。


3.    Maven的作用


  3.1 优秀的构建工具

    构建自动化

    在实际的工作中我们会发现,除了编写源代码,我们每天有相当一部分时间花在了编译、运行单元测试、生成文档、打包和部署等繁琐且不起眼的工作上,即所谓的“构建”上。如果现在还手工这样做,成本非常高,于是有人用软件的方法让这一系列工作完全自动化,使得软件构建可以像全自动流水线一样,只需要一条简单的命令,所有繁琐的步骤都能自动完成,很快就能得到最终结果。

    Maven是一个异常强大的优秀的构建工具,能够帮我们自动化构建过程,从清理、编译、测试到生成报告,再到打包和部署。我们不用一遍遍地输入命令、点击鼠标,我们要做的是使用Maven配置好项目,然后输入简单命令(如mvnclean install),Maven会帮我们处理那些繁琐的任务。

    消除构建的重复

         我们一直在避免重复,设计的重复、编码的重复、文档的重复,当然还有构建的重复。Maven最大化地消除了构建重复,抽象了一个完整的构建生命周期模型,并且为绝大部分的构建任务提供了已实现的插件。如果遵循这个模型,可以避免很多不必要的错误,可以直接使用大量成熟的Maven插件来完成我们的任务。即,Maven抽象了构建过程,提供了构建任务的实现

    标准化构建过程

         或者可以说Maven制定了一套标准。如果不用Maven,十个项目可能有十套构建方式;有了Maven之后,所有项目的构建命令都是简单一致的,而且Maven是夸平台的,在Windows、Linux、Mac等上的命令也都相同。这极大地促进了不必要的学习成本,而且有利于促进项目团队的标准化。

    或者说Maven提倡约定优于配置(Convention Over Configuration),Maven对于项目目录结构、测试用例命名方式等内容都有既定的规则,只要遵循了这些成熟的规则,用户在项目间切换的时候就免去了额外的学习成本。


  3.2 依赖管理工具

       Java不仅是一门编程语言,还是一个平台。同理,Maven不仅是构建工具,还是一个依赖管理工具。它为全世界的Java开发者提供了一个免费的“中央仓库”,在其中几乎可以找到任何流行的开源类库。通过一些Maven的衍生工具(如Nexus),我们还能对其进行快速地搜索,只要定位了坐标(配置了依赖关系)Maven就能帮我们自动下载构件,省去了手工劳动。

       在开源的年代,几乎任何Java应用都会借用一些第三方的开元类库,这些类库都可以通过依赖的方式引入到项目中来。随着依赖的增多、版本不一致、版本冲突、依赖臃肿等问题都会接踵而至。手工解决这些问题是十分费时费力的,幸运的是Maven提供了一个优秀的解决方案,它通过一个坐标系统准确的定位每一个构件(artifact),也就是通过一组坐标Maven能找到任何一个类库(如jar文件)。Maven给这个类库引入了经纬,让它们变得有序,于是我们可以借助它有序的管理依赖,轻松地解决那些繁杂的依赖问题。

       上面说到Maven 坐标能够确定一个构件。换句话说,我们可以用它来解决依赖关系。在 POM 中,groupId,artifactId, packaging, version 叫作 maven 坐标,它能唯一的确定一个构件。有了 maven 坐标,我们就可以用它来指定我们的项目所依赖的其他项目,插件,或者父项目。一般 maven 坐标写成如下的格式: groupId:artifactId:packaging:version

  在 POM 中,依赖关系是在 dependencies 部分中定义的。例如,我们用dependencies 定义对于 junit 的依赖:

[html]  view plain  copy
  1. <dependencies>   
  2.   <dependency>   
  3.     <groupId>junit</groupId>   
  4.     <artifactId>junit</artifactId>   
  5.     <version>3.8.1</version>   
  6.     <scope>test</scope>   
  7.   </dependency>   
  8. </dependencies>   

  3.3 项目信息管理工具

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


4.    与其它构建工具对比

       Make也许是最早的构建工具,它由一个名为Makefile的脚步文件驱动。它的强大之处在于它可以利用所有系统的本地命令,尤其是Unix、Linux系统,丰富的功能强大的命令能够帮助Make快速高效的完成任务。但是Make将自己和操作系统绑定在一起了,也就是说,使用Make将不能(至少很难)跨平台构建。而且Makefile的语法也很有问题,很多人抱怨Make构建失败的原因,往往是一个难以发现的空格或Tab使用错误。

       Ant(另一个整洁的工具-Another Neat Tool)最早用来构建著名的Tomcat。与Make一样,都是过程式的,开发者显式地指定每一个日标,以及完成该目标所需要执行的任务。针对每一个项目,开发者都需要重新编写这一过程,这里其实隐含着很大的重复。Maven是声明式的,项目构建过程和过程各个阶段所需的工作都由插件实现,并且大部分插件都是现成的,开发者只需要声明项目的基本元素,Maven就执行内置的、完整的构建过程。这在很大程度上消除了重复。此外,Ant本身是没有依赖管理的,幸运的是,Ant用户现在可以借助lvy管理依赖。而对于Maven用户来说,依赖管理是理所当然的,Maven不仅内置了依赖管理,更有一个可能拥有全世界最多Java开源软件包的中央仓库,Maven用户无需任何配置就可以无偿享用。


5.    总结

  Maven 是一个基于项目对象模型(POM)的,提倡约定优于配置(ConventionOver Configuration)的,跨平台的项目管理和构建自动化工具。首先它是一个优秀的构建工具(构建自动化、消除构建重复、标准化构建过程),其次它还是一个依赖管理工具、项目信息管理工具。



我们最能感受到的Maven的好处应该是它的“自动化构建”与“管理依赖关系”两大功能,下面就看围绕这两大功能的Maven中的核心概念。


1.    项目目录

  Maven 使用约定优于配置的原则 。它要求在没有定制之前,所有的项目都有如下的主要目录结构:


  

  一个 maven 项目在默认情况下会产生 JAR 文件,另外 ,编译后 的 .classe文件 会放在 ${basedir}/target/classes 下面;JAR文件会放在${basedir}/target 下面。如下图所示:


  


2.    POM (Project Object Model)


  2.1  概念介绍

    一个项目所有的配置都放置在 POM 文件中:定义项目的类型、名字,管理依赖关系,定制插件的行为等等。比如说,你可以配置 compiler 插件让它使用 java1.5 来编译。

[html]  view plain  copy
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.    <modelVersion>4.0.0</modelVersion>   
  4.   
  5.    <groupId>com.mycompany.helloworld</groupId>   
  6.    <artifactId>helloworld</artifactId>   
  7.    <version>1.0-SNAPSHOT</version>   
  8.    <packaging>jar</packaging>   
  9.   
  10.    <name>helloworld</name>   
  11.    <url>http://maven.apache.org</url>   
  12.   
  13.    <properties>   
  14.      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>   
  15.    </properties>   
  16.   
  17.    <dependencies>  
  18.      <dependency>   
  19.        <groupId>junit</groupId>   
  20.        <artifactId>junit</artifactId>   
  21.        <version>3.8.1</version>   
  22.        <scope>test</scope>   
  23.      </dependency>   
  24.    </dependencies>   
  25.   </project>      

    在 POM 中,groupId,artifactId, packaging, version 叫作 maven 坐标,它能唯一的确定一个构件。有了 maven 坐标,我们就可以用它来指定我们的项目所依赖的其他项目,插件,或者父项目。


    


    通常,大项目一般会分成几个子项目。在这种情况下,每个子项目就会有自己的 POM 文件,然后它们会有一个共同的父项目。这样只要构建父项目就能够构建所有的子项目了。子项目的 POM 会继承父项目的 POM。另外,所有的 POM都继承了一个 Super-POM。Super-POM 设置了一些默认值,比如在前面提到的默认的目录结构,默认的插件等等,它遵循了惯例优于配置的原则。如下图:


    


  2.2  Pom文件的继承与聚合

  继承

    开发中一般将公共的配置——依赖关系(包括公共的类库、插件、信息配置)放到一个父项目的pom文件,然后其它项目的pom文件,都继承该pom文件。继承的代码如下:


    


    这里需要注意,子pom文件不是一旦继承了父pom就会无条件地继承它所有的依赖关系,即插件、类库等。如果子pom想继承父pom的某个插件,只需要引入父pom中该插件的groupId与artifactId信息(不用写该插件其它的配置信息)即可。这样子pom是可以有选择性的继承它自己所需要的东西。


    


  聚合

    即大项目中一般会有一个空的Maven项目(只有pom文件,没有java代码)作为父项目,该项目的Pom文件(Modules标签中)聚合了其它子项目的Pom文件,然后只要构建父项目就能够构建所有的子项目了。


    


3.    Maven 插件

       Maven的每个生命周期都有一个“插件”(目标)来保证。在前面,我们用了 mvn archetype:generate 命令来生成一个项目。那么这里的 archetype:generate 是什么意思呢?archetype是一个插件的名字,generate是目标(goal)的名字。这个命令的意思是告诉 maven 执行archetype 插件的 generate 目标。插件目标通常会写成 pluginId:goalId

  一个目标是一个工作单元,而插件则是一个或者多个目标的集合。比如说Jar插件,Compiler插件,Surefire插件等。从看名字就能知道,Jar插件包含建立Jar文件的目标, Compiler 插件包含编译源代码和单元测试代码的目标。Surefire 插件的话,则是运行单元测试。

  看到这里,估计你能明白了,mvn本身不会做太多的事情,它不知道怎么样编译或者怎么样打包。它把构建的任务交给插件去做。插件定义了常用的构建逻辑,能够被重复利用。这样做的好处是,一旦插件有了更新,那么所有的 maven 用户都能得到更新。

  Maven的插件服务非常强大,比如你想打包源代码为rar压缩格式,比如你想执行sql命令,等等,只需要找到相应的Maven插件,配置好即可使用,如下图:


  


4.    Maven 生命周期

  在前面,我们用的第二个命令是:mvn package。这里的 package 是一个maven的生命周期阶段 (lifecyclephase )。生命周期指项目的构建过程,它包含了一系列的有序的阶段 (phase),而一个阶段就是构建过程中的一个步骤。

  那么生命周期阶段和上面说的插件目标之间是什么关系呢?插件目标可以绑定到生命周期阶段上。一个生命周期阶段可以绑定多个插件目标。当 maven 在构建过程中逐步的通过每个阶段时,会执行该阶段所有的插件目标。

  maven 能支持不同的生命周期,但是最常用的是默认的Maven生命周期 (default Mavenlifecycle )。

  Maven有3套生命周期,clean、compile、site,在配置插件的时候一般都要配置插件的执行时机(即Maven的某一个生命周期),如下图:


  


  这里不一 一介绍生命周期,只介绍几个常用的:

  Clean

    pre-clean:执行一些需要在clean之前完成的工作

    clean移除所有上一次构建生成的文件(清除Target文件夹)

    post-clean:执行一些需要在clean之后立刻完成的工作

  Compile

         process-resources:复制并处理资源文件至目标目录,准备打包

         compile:编译项目源代码

         process-test-resources:复制并处理资源文件至目标测试目录

         test-compile:编译测试源代码

         test:使用合适的单元测试框架运行测试,这些测试代码不会被打包或部署。

         package接受编译好的代码,打包成可发布的个格式,如jar

         install将包安装至本地仓库,以让其它项目依赖

         deploy将最终的包复制到远程仓库,以让其它开发人员与项目共享。

  Site

    pre-site:执行一些需要在生成站点文当前完成的工作。

    site生成项目的站点文档。

    post-site:执行一些需要在生成站点文档之后完成的工作,并未部署做准备。

    site-deploy:将生成的站点文档部署到服务器上。


5.    Maven 依赖管理


  5.1  概念介绍

    之前我们说过,maven 坐标能够确定一个项目。换句话说,我们可以用它来解决依赖关系。在 POM 中,依赖关系是在 dependencies部分中定义的。在上面的 POM 例子中,我们用 dependencies 定义了对于 junit 的依赖:

[html]  view plain  copy
  1. <dependencies>   
  2.     <dependency>   
  3.       <groupId>junit</groupId>   
  4.       <artifactId>junit</artifactId>   
  5.       <version>3.8.1</version>   
  6.       <scope>test</scope>   
  7.     </dependency>   
  8.   </dependencies>   

    我们依赖的类库,我们都可以到Maven的中央仓库去找,例如下图找Hibernate的核心包:mvnrepository.com/search.html?query=hibernate

    


    上面的例子很简单,但是实际开发中我们会有复杂得多的依赖关系,因为被依赖的 jar 文件会有自己的依赖关系。那么我们是不是需要把那些间接依赖的 jar 文件也都定义在POM中呢?答案是不需要,因为 maven 提供了传递依赖的特性。

    所谓传递依赖是指 maven 会检查被依赖的 jar 文件,把它的依赖关系纳入最终解决的依赖关系链中。针对上面的 junit 依赖关系,如果你看一下 maven 的本地库你会发现 maven 不但下载了 junit-3.8.1.jar,还下载了它的 POM 文件。这样 maven 就能检查 junit 的依赖关系,把它所需要的依赖也包括进来。

    在 POM 的 dependencies 部分中,scope 决定了依赖关系的适用范围。我们还可以指定scope 为 provided,意思是 JDK 或者容器会提供所需的jar文件。比如说在做web应用开发的时候,我们在编译的时候需要servlet API jar 文件,但是在打包的时候不需要把这个 jar文件打在 WAR 中,因为servlet容器或者应用服务器会提供的。

    scope 的默认值是 compile,即任何时候都会被包含在 classpath 中,在打包的时候也会被包括进去。


  5.2  依赖的范围(scope)

    有如下几种:

    test

      指测试范围有效,编译和打包时都不使用该依赖。

    compile:(为默认值)

      编译范围有效,编译和运行(打包)时都会将依赖存进去

    provided

      测试、编译范围都有效,最后生成war包时不会加入,例如:servlet-api,编译的时候需要该文件,但是在打包的时候不需要把这个 jar 文件打在 WAR 中,因为servlet容器或者应用服务器会提供的。打进去会出现冲突。

    runtime

          编译时不依赖,运行(打包)时依赖

    


  5.3  依赖的传递(间接依赖)

    首先,依赖是可以传递的

    


    当依赖层级相同的时候,相同的东西,会采用,近者优先。当依赖层级不同时,层级(最短)近的优先。

    


  5.4  排除依赖

    当依赖包发生冲突时,我们可以用exclusion标签排除依赖

    


6.     Maven仓 库


  6.1  概念介绍

    主要介绍3种仓库,本地仓库、私服(Nexus)、中央仓库。3者的关系如下图所示:


    


    首先,Maven本身自带一个本地仓库;然后它又为全世界的Java开发者提供了一个免费的“中央仓库”,在其中几乎可以找到任何流行的开源类库;由于中央仓库是在外网中的,如果没有私服(Nexus),本地仓库就会频繁地与中央仓库即互联网打交道,这样效率很低,所以在两者之间衍生出了一个“私服——Nexus”,私服存在于局域网中,这样本地仓库就不用频繁地与外网中的中央仓库交互,所以效率就会大大提高。


  6.2  修改本地仓库

    本地仓库的位置默认为:${user.home}/.m2/repository。例如下图:

    


    修改本地仓库位置的步骤如下:


    新建本地工厂的文件夹,如我建在,与Maven同目录下:


    


    将F:\maven\apache-maven-3.2.3\conf文件夹下的Settings.xml文件夹拷贝到上面新建的本地工厂的同级目录位置


    


    修改本地工厂同目录下的Settings.xml文件中的内容,设置本地仓库的位置为,上面新建的仓库的目录


    

    到此完成。


  6.3  中央仓库的位置

    中央仓库的位置在如下目录中:

    ${MAVEAN_HOME}\lib\maven-model-builder.jar\org\apache\maven\mode\pom.xml中,如下图:


    

    Nexus的安装与介绍在后面的文章中介绍。


7.    总结

    Maven提倡“约定优于配置”,它的项目的目录结构,测试方法的命名等都有一定的要求。

    Maven是基于Pom的,一个Maven项目所有的配置都放置在 POM 文件中:定义项目的类型、名字,管理依赖关系,定制插件的行为等等。Pom文件之间还可以继承、聚合等。

    Maven很强大,很大一方面是它的插件服务非常强大,Maven本身基本不怎么做事,它基本是调用一些插件来做事。Maven有3套生命周期,clean、compile、site,而每个生命周期中的每个步骤都有一个目标插件来支持。配置每个插件时也都会指明插件的运行时机(即Maven生命周期中的某个步骤)。

    Maven自带强大的依赖管理系统,配置了某个依赖,确定了某个构件的坐标,Maven就能帮我们自动下载构件。

    Maven本身自带一个本地仓库;然后它又为全世界的Java开发者提供了一个免费的“中央仓库”,为了解决本地仓库频繁与中央仓库(存在于外网中)交互,导致效率低的问题,又衍生出了私有仓库,即私服(Nexus)。



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值