Maven

Maven

Maven简介

介绍Maven前,我们要先弄清楚什么是构建?

我们工作时,除了编写源代码,每天有一部分时间都花在了编译、运行单元测试、生成文档、打包和部署上面,这就是构建。多次重复的做这种工作,浪费了大量程序员的时间,所以有人用软件使这一系列操作完全自动化,只需要一条命令,这些繁琐的操作会很快完成。

强大的Maven

Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具。是一个异常强大的构建工具,能帮我们自动化构建过程,从编译、运行单元测试、生成文档、打包和部署,我们只需要输入见得的Maven命令即可。

Maven是java编写的,因此可以跨平台。总的来说,Maven 简化了工程的构建过程,并对其标准化。它无缝衔接了编译、发布、文档生成、团队合作和其他任务。Maven 提高了重用性,负责了大部分构建相关的任务

Maven不仅仅是构建工具,还是依赖管理工具和项目信息管理工具,还有一个强大的功能就是能够自动下载项目依赖的第三方库,Maven通过坐标来准确的定位到每一个jar包,并自动帮我们下载。

Maven的安装和配置

1.先从官网下载Maven,我这里下载的最新版 apache-maven-3.5.0-bin 
2.下载成功后要配置Maven环境变量

这里写图片描述

这里写图片描述

3.测试是否安装成功,在系统命令行中执行命令:mvn –v

这里写图片描述

4.在Maven安装的目录的conf下有settings.xml文件,这是Maven的全局配置文件 
 我们可以在这儿配置本地仓库的地址,仓库后面会详解,里面会存放Maven下载的插件等
 仓库地址默认系统的用户目录下的.m2/repository 
 我们自己来改变一下,当然我们

这里写图片描述

5.我们先运行一条简单的命令 mvn help:system,该命令会打印出所有的java系统属性和环境变量。
运行这条命令主要目的是第一次运行Maven命令时,会自动下载Maven的插件,包括pom文件和jar,都被下载到了本地仓库中。  

这里写图片描述

这里写图片描述

简单的Maven入门项目

安装好Maven后,我们来手动搭建一个简单的Maven项目,Maven项目是约定大于配置,有固定的结构。

Maven项目的结构
Project
    |--src(源码包)
        |--main(正常的源码包)
            |--java(.java文件的目录)
            |--resources(资源文件的目录)
        |--test(测试的源码包)
            |--java
            |--resources
    |--target(class文件、报告等信息存储的地方)
    |--pom.xml(maven工程的描述文件) 
1.我们创建一个HelloWorld的项目,按照Maven项目的结构创建
  只需创建src和pom.xml即可,target文件夹Maven会帮我们生成    

这里写图片描述

2.我们来编写一下pom.xml ,Maven的核心是pom.xml,pom定义了项目的基本信息,描述项目如何构建,声明项目依赖等。


<?xml version="1.0" encoding="UTF-8"?>
<!--project是pom文件根元素,声明了一些命名空间-->
<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/xsd/maven-4.0.0.xsd">
  <!-- 指定了当前POM模型的版本,只能是4.0.0 -->
  <modelVersion>4.0.0</modelVersion>
  <!-- groupId 组织名称,定义了项目属于哪个组 -->
  <groupId>com.cad.maven</groupId>
  <!-- artifactId,定义了当前项目在组中的唯一标识。一般是项目名称 -->
  <artifactId>HelloWorld</artifactId>
  <!-- 当前项目版本号:每个工程发布后可以发布多个版本,依赖时调取不同的版本,使用不同的版本号 -->
  <version>0.0.1</version>
  <!-- 名称:可省略,提供一个更友好的名称 -->
  <name>Hello</name>


</project>
3.创建主代码HelloWorld.java,放在src/main/java 下面 ,该类的包名和类名应该和pom中定义的groupId和
artifactId一样 

    package com.cad.maven;

    public class HelloWorld{

        public String sayHello(String name){
            return "hello"+name;
        }
    }

4.使用Maven进行编译,在项目根目录下使用命令 mvn -compile
  第一次编译还是会下载很多插件,jar包等
  编译成功后会在项目根目录下生成target目录,里面包含了.class文件和一些信息    

这里写图片描述

编写测试代码

1.测试代码按照约定应该位于src/test/java 路径下,我们使用我们熟悉的junit来进行测试,但是我们没有jar包,这时候我们可以使用maven为我们添加一个jUnit依赖 

<?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/xsd/maven-4.0.0.xsd">
  <!-- 版本:4.0.0 -->
  <modelVersion>4.0.0</modelVersion>
  <!-- 组织名称:暂时使用 组织名称+项目名称 作为组织名称 -->
  <!-- 组织名称:实际名称 按照访问路径规范设置,通常以功能作为名称:eg: junit spring -->
  <groupId>com.cad.maven</groupId>
  <!-- 项目名称 -->
  <artifactId>HelloWorld</artifactId>
  <!-- 当前项目版本号:同一个项目开发过程中可以发布多个版本,此处标示0.0.1版 -->
  <!-- 当前项目版本号:每个工程发布后可以发布多个版本,依赖时调取不同的版本,使用不同的版本号 -->
  <version>0.0.1</version>
  <!-- 名称:可省略 -->
  <name>Hello</name>

  <!-- 依赖关系 -->
    <dependencies>
        <!-- 依赖设置 -->
        <dependency>
            <!-- 依赖组织名称 -->
            <groupId>junit</groupId>
            <!-- 依赖项目名称 -->
            <artifactId>junit</artifactId>
            <!-- 依赖版本名称 -->
            <version>4.9</version>
            <!-- 依赖范围:test包下依赖该设置 -->
            <scope>test</scope>
        </dependency>   
    </dependencies>      
</project>


Maven会自动访问中央仓库下载依赖的jar包。
2.编写测试类,使用 Assert断言我们的结果是否为hellomaven

package com.cad.maven; 

import static org.junit.Assert.*;
import org.junit.Test; 

public class TestHelloWorld{

    @Test
    public void testsayHello(){
        HelloWorld hw=new HelloWorld();
        String result=hm.sayHello("maven");
        AssertEquals("hellomaven",result);
    }
}
3.运行mvn clean test命令 

 会显示测试报告,通过了多少、失败了多少、跳过了多少等

这里写图片描述

项目打包

将我们的项目打包,包可以指定很多类型,后面我们会详细介绍。不指定的话默认是jar包,
我们使用mvn package命令进行打包,会在target目录下有我们打好的jar包  

这里写图片描述

这里写图片描述

项目安装

我们其他的Maven项目如何使用我们的项目呢,我们可以使用install命令将我们的jar包安装到本地仓库,然后在其他项目中通过gav来引用。

mvn install

这里写图片描述

使用Archetype生成项目骨架

Maven项目有一些约定,在根目录放pom.xml文件,src/main/java中放源码等等。如果我们每次创建Maven项目都需要自己来创建这个骨架的话,估计会烦的要命。Maven为我们提供了Archetype来帮助我们快速构建项目骨架。

我们在使用mvn archetype:generate命令生成项目骨架,Maven会有很多骨架供我们选择,也会提供一个默认的骨架,我们直接回车,然后会让我们输入groupid、artifactid、version、package等,然后就可以生成完整的项目骨架,极其方便。

这里写图片描述

常用Maven命令总结

Maven的命令要在根在目录中去执行

Mvn compile: 编译命令
Mvn clean:   清除命令,清除已经编译好的class文件,具体说清除的是target目录中的文件
Mvn test:    测试命令,该命令会将test目录中的源码进行编译
Mvn package: 打包命令
Mvn install: 安装命令,会将打好的包,安装到本地仓库

命令是可以组合的:
    Mvn clean compile:先清空再编译

    mvn clean test命令:先执行clean,再执行test,通常应用于测试环节

    mvn clean package:先执行clean,再执行package,将项目打包,通常应用于发布前
        执行过程:
            清理————清空环境
            编译————编译源码
            测试————测试源码
            打包————将编译的非测试类打包 

    mvn clean install:先执行clean,再执行install,将项目打包,通常应用于发布前
        执行过程:
            清理————清空环境
            编译————编译源码
            测试————测试源码
            打包————将编译的非测试类打包
            部署————将打好的包发布到资源仓库中

M2Eclipse的使用

我们的项目一般都是在IDE中进行编写,Eclipse有一款强大的Maven插件M2Eclipse。新版的Eclipse中都自带这款插件。

1.我们在Eclipse中创建一个Maven项目,选择new->Maven Project,选择默认的工作空间即可,点击next 

这里写图片描述

2.这一步会让我们选择骨架,我们选择quickstart

这里写图片描述

3.输入坐标 

这里写图片描述

4.点击finish,完成创建

执行Maven命令

我们在项目上右键run as会出现一些常用的Maven命令。

这里写图片描述

如果这些命令不能满足我们要求,我们需要别的命令怎么办呢?我们只需要选择Maven build就可以自己输入Maven命令,在这里输入Maven命令不需要加mvn。点击run即可运行

这里写图片描述

Maven坐标

Maven的很强大的一个功能就是管理项目依赖,为了能自动化的精确获取到项目依赖,Maven就必须为其唯一标识,Maven通过坐标来构建唯一标识。

平面几何中,使用(x,y)坐标来表示平面中的任何一个点。Maven中拥有数量巨大的构件,就是jar、war等文件,Maven自己创建了一种坐标规则,只要我们指定争取的坐标,Maven就会到中央仓库中下载这些构建,Maven的中央仓库中包含了世界上流行的大部分构件。

坐标详解

我们来看一组坐标 

     <groupId>com.cad.maven</groupId>
     <artifactId>HelloWorld</artifactId>
     <version>0.0.1</version>
     <packaging>jar</packaging> 
  • groupId:组织名称。项目属于哪个组。例如Spring-core,Spring-context都是属于SpringFramework组的。

  • artifactId:项目名称。

  • version:定义当前项目的版本

  • packaging:定义项目的打包方式。例如jar、war。不指定默认为jar

Maven依赖管理

根元素project下的dependencies可以包含一个或多个 dependency元素,以声明一个或多个项目依赖。
每个依赖可以包含以下元素。

<groupId>:依赖组织名称    
<artifactId>:依赖项目名称
<version>:版本 
<scope>:依赖范围
<type>:依赖类型,对应于项目坐标定义的packing。默认值为jar
<optional>:标记依赖是否可选 
<exclusions>:用来排除传递性依赖 

依赖范围

我们在前面的测试例子中,依赖的JUnit设置了一个<scope>为test,为什么这么设置呢?这就涉及到依赖范围的概念。 

首先我们需要知道主项目代码在编译时需要使用一套classpath,编译主代码需要使用jar包,该jar包就以依赖的方式被引入到classpath中。Maven在编译和执行测试代码时,会使用另一套classpath,然后例如junit包等也会被引入这个classpath中。最后,实际运行项目时,又会使用另一套classpath,一些spring等jar包需要在该classpath中,而junit等就不需要。 

依赖范围就是用来控制依赖应该在何时存在,例如junit包只需要在测试时存在,项目正式运行时就不需要了。

Maven有以下几种依赖范围

  • compile:没有指定,默认使用该依赖范围。使用此依赖范围,对于主代码、测试、运行时都会被引入各自的classpath。例子是spring-core,在主代码、测试、运行时都需要这个依赖。

  • test:测试依赖范围。使用此依赖范围的Maven依赖,只会被测试classpath引入。例子是JUnit,只有在测试时需要。

  • provided:使用此依赖范围的Maven依赖,会被主代码、测试等classpath引入,在运行时无效。例子是servlet-api,编译主代码和测试时需要,但在运行时由于容器会提供,所以可能会出现冲突,就不需要Maven再引入依赖。

  • runtime:运行时依赖范围。使用此依赖范围的Maven依赖,只有项目运行时会引入依赖。例子是JDBC驱动,在编译主代码时无效,只有测试运行还有运行时需要引入。

这里写图片描述

依赖传递

什么是依赖传递呢?

我们说一个简单的例子,例如我们的B项目依赖C项目,我们的A项目依赖于B项目,C项目的很多依赖在A项目中也需要,Maven有依赖传递机制,我们A项目既然依赖了B项目,就不需要考虑B项目依赖了什么,也不用担心使用不了C项目的依赖,再重复定义依赖,Maven会解析各个直接依赖的pom文件,将那些间接依赖引入到当前项目中。

依赖传递范围

依赖范围会对依赖传递产生影响。

我们上面的例子中,A项目依赖B项目,在A项目的pom文件中设置B项目的依赖范围为compile,B项目依赖C项目,在B项目的pom文件中设置c项目的依赖范围为compile。那么A项目对于C项目的传递性依赖的范围就是compile。 


A项目依赖于B项目,B项目依赖于C项目。我们说A对B是第一直接依赖,B对C是第二直接依赖,A对C是间接依赖。

这里写图片描述

第一直接依赖的范围和第二直接依赖的范围决定了依赖传递范围。我们用下图来说明一下。
左边第一列代表第一直接依赖的范围,上面第一行代表第二依赖的范围,中间表示传递依赖范围。

这里写图片描述

我们再来举个例子来理解该表,例如我们的A项目依赖Spring-core.jar,这是第一直接依赖,其依赖范围是test。而Spring-core.jar又依赖于commons-logging.jar,这是第二直接依赖,其依赖范围是compile。因此,对照表,即可得知,A项目是commons-logging.jar的一个范围是test的传递性依赖,也就是说在测试的时候才会将commons-logging.jar引入。我们来验证一下 
1.我们创建第一个项目FirstMaven 

主代码:

    package com.cad.maven.FirstMaven;

    public class FirstMaven 
    {
        public String sayHello(String name) {
            return "hello"+name;
        }
    } 
pom文件:

    <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/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>

      <groupId>com.cad.maven</groupId>
      <artifactId>FirstMaven</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>

      <name>FirstMaven</name>
      <url>http://maven.apache.org</url>

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>

      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>compile</scope>
        </dependency>
      </dependencies>
    </project>
2.创建第二个项目,SecondMaven,我们在pom文件中依赖第一个项目,依赖范围设置为compile,由于第一个项目中依赖了junit,并且范围设置为compile。所以第二个项目中也自动依赖了junit。 


主代码 

    package com.cad.maven.SecondMaven;

    import com.cad.maven.FirstMaven.FirstMaven;

    class SecondMaven 
    {
        public String sayHello(String name) {
            FirstMaven fm=new FirstMaven();
            return fm.sayHello(name);
        }
    }
pom文件 

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.cad.maven</groupId>
  <artifactId>SecondMaven</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>SecondMaven</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.cad.maven</groupId>
      <artifactId>FirstMaven</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project> 
3.我们创建第三个项目,ThirdMaven,依赖第二个项目,并且依赖范围设置为test 

    public class ThirdMaven 
    {
        public static void main( String[] args )
        {
           ThirdMaven tm=new ThirdMaven();  
           String result=tm.sayHello();
           System.out.println(result);
        }

        public String sayHello() {
            return new SecondMaven().sayHello("maven");
        } 
    }
pom文件 

    <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/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>

      <groupId>com.cad.maven</groupId>
      <artifactId>ThirdMaven</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>

      <name>ThirdMaven</name>
      <url>http://maven.apache.org</url>

      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>

      <dependencies>
        <dependency>
          <groupId>com.cad.maven</groupId>
          <artifactId>SecondMaven</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
4.这时候我们的依赖传递范围为test,就说明只在测试时能引入,所以这时候在主代码运行会报错,而测试时候运行则不会报错。
总结:
    当第二依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致。
    当第二直接依赖的范围是test的时候,依赖不会得以传递。
    当第二依赖的范围是provided的时候,只传递第一直接依赖范围也为provided的依赖,且传递性依赖的范围同样为 provided;
    当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile例外,此时传递的依赖范围为runtime;

依赖冲突

什么是依赖冲突呢?

    比如我们A项目依赖B项目,B项目依赖C项目。B项目依赖JUnit3.0版本,C项目依赖JUnit4.0版本,并且依赖范围都是compile。那么这时候就出现了冲突,A项目会依赖哪个呢? 

    Maven使用了就近原则,会使用距离A项目近的版本,所以会使用B项目的JUnit3.0版本。 

    如果一个pom文件中引入了两个不同版本的相同依赖,那么越靠近pom文件下面的越近。

可选依赖

什么是可选依赖呢?

    比如我们A项目依赖B项目,B项目依赖C项目,设置的依赖范围都是compile。但是我们的A项目根本就不需要C项目,这时候就可以设置C项目的可选依赖,有个 <optional></optional>标签,设置为true则依赖不会传递,设置为false,依赖继续传递,这就是可选依赖。我们把C项目的可选依赖设置为true,A项目中就不会再引用C项目。 

排除依赖

我们的可选依赖可以让某个依赖不再传递,但这时就出现了一种情况,我们D依赖A项目,但是D项目也需要C,这时候C项目传递不过来,就产生了很多麻烦。这时候可以使用排除依赖,排除依赖可以把自己不需要的依赖给排除。

我们在C项目排除A项目 

<dependencies>
    <dependency>
      <groupId>com.cad.maven</groupId>
      <artifactId>SecondMaven</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>test</scope>
      //排除A项目
      <exclusions>
        <exclusion>
            <groupId>com.cad.maven</groupId>
            <artifactId>FirstMaven</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
  </dependencies>

归类依赖

    我们的项目依赖spring,Spring项目分为很多个模块,例如Spring-core-4.0.jar,Spring-bean-4.0.jar等等。   等到我们项目需要更新Spring的时候,由于版本号都一样,所以我们是否可以将版本号给用一个常量存放,然后更新Spring时只需要改变常量的值即可。这样可以省去很多时间。 
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.cad.maven</groupId>
  <artifactId>ThirdMaven</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>ThirdMaven</name>
  <url>http://maven.apache.org</url>

  <properties>
    <springframework.version>4.5</springframework.version>
  </properties> 

 <dependencies> 
     <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${springframework.version}</version>
     </dependency> 

     <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${springframework.version}</version>
     </dependency> 

  </dependencies>
</project>

优化依赖

通过前面的学习了解,Maven会自动解析所有直接依赖和传递依赖,并且判断依赖范围,最后项目得到的的依赖被称为已解析依赖。

我们可以通过mvn dependency:list来查看当前项目已解析依赖并且显示其范围  

这里写图片描述

我们可以通过mvn dependency:tree命令来查看当前项目依赖树 

这里写图片描述

Maven仓库

Maven可以在某个统一的位置存储所有项目的依赖,这个位置就是仓库。Maven项目中只需要声明依赖的坐标,Maven会根据坐标自动寻找仓库中的依赖,并使用他们。而我们的项目也可以安装部署到仓库中,使其他项目使用。

根据Maven坐标定义每个构建在仓库中唯一存储路径大致为:groupId/artifactId/version/artifactId-version.packaging。

仓库的分类

Maven仓库分为本地仓库和远程仓库。Maven根据坐标寻找依赖时,会先到本地仓库查找,如果有则直接使用,如果没有则到远程仓库查找,如果查找到则下载到本地仓库使用,没有查找到就报错。

远程仓库又分为中央仓库和私服还有其他公开的远程仓库。私服是一种特殊的远程仓库,我们可以在公司内部部署一个私服,这样每个员工使用依赖时就不用每个人都去中央仓库下载,而是去局域网的私服下载,还可以把公司内部的项目放在私服上,供所有人使用,节省了带宽和时间。

本地仓库

默认情况下,本地仓库的地址是用户目录下的.m2/repository/ ,但是我们可以编辑settings.xml文件来自己设置目录,前面我们有讲过,就不再多说。

中央仓库

默认的中央仓库地址是http://repo1.maven.org/maven2。中央仓库包含了世界上大部分开源依赖。

私服

私服架设在局域网内,供局域网内的用户使用。Maven需要下载依赖时,先请求私服,如果私服没有,则从外部的远程仓库下载,自己还可以向私服上上传自己的项目,供局域网使用。

私服有很多优点。

  • 节省自己带宽:大量对于外部仓库的访问会占用很多带宽。
  • 没网的时候也可以使用
  • 可以部署自己的项目

后面我们会详细介绍私服的搭建。

配置其他远程仓库

有时候我们默认的中央仓库无法满足我们的需求,可能项目需要的依赖存在于其他公开的远程仓库。例如JBoss Maven仓库,可以在我们的pom文件中配置该仓库。

配置JBoss Maven仓库 

  <repositories>
    <repository>
        <!--唯一id-->
        <id>jboss</id>
        <name>JBoss Repository</name>
        <!--仓库的url地址-->
        <url>http://repository.jboss.com/maven2/</url> 
        <!--开启发布版本下载支持-->
        <releases>
            <enabled>true</enabled>
        </releases>
        <!--关闭快照版本下载支持-->
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <!--使用默认布局-->
        <layout>default</layout>
    </repository>
  </repositories>

快照版本

Maven中任何一个项目依赖都需要有唯一的版本。例如1.0, 2.3.1 , 4.2-SNAPSHOT.
其中1.0,2.3.1都是发布版本,4.2-SNAPSHOT是快照版本。

为什么要区别发布版本和快照版本呢?

A开发一个项目的B模块,C开发D模块,D模块依赖B模块。A需要经常将自己的B模块更新供D使用。Maven每个坐标都是唯一的,A将自己的项目发布为2.1版本供C调用,那么有一些微小的改动,就需要发布2.2,2.3等版本,造成版本号的滥用。Maven的快照就是解决这个问题,A只需要将自己的版本设置为2.1-SNAPSHOT,发布到私服中,Maven会自动为项目打上时间戳,有了时间戳,Maven就能找到该项目的最新版本,C开发D模块时,D模块会自动的检查模块B的2.1-SNAPSHOT是否是最新,发现有更新便下载。

快照版本应该只在组织内部或模块依赖间使用,真正发布还是要发布正式版。

Maven生命周期

什么是生命周期?

Maven还没出现之前,项目构建的生命周期就存在。程序员每天都对项目进行清理、编译、测试、打包等工作,各个公司都一样,有的是手工完成,有的可以编写自动化脚本完成,虽然过程可能有点细微的不一样,但非常类似。Maven的生命周期就是对所有的构建过程进行抽象和统一,总结了一套高度完善、易扩展的生命周期,包含了清理、编译、测试、打包、部署等几乎所有的构建步骤。Maven的生命周期是抽象的,不做任何事情,都由各种插件完成。简单的说,生命周期可以理解为构建步骤的集合。

Maven有3套生命周期,clean、default、site。生命周期包括多个阶段,这些阶段有一定的顺序,并且执行后面的阶段前面的阶段也会自动执行。例如clean的生命周期包含pre-clean、clean、post-clean,当用户执行pre-clean命令时,只有pre-clean执行,当用户执行clean时,会执行pre-clean和clean命令,当用户执行post-clean命令时,会执行三个命令。

clean生命周期

  • pre-clean:执行一些清理前需要完成的工作
  • clean:清理上一次构建生成的文件
  • post-clean:执行一些清理后需要完成的工作

default生命周期

validate 
generate-sources 
process-sources 
generate-resources 
process-resources 复制并处理资源文件,至目标目录,准备打包。 
compile 编译主项目的源代码。 
process-classes 
generate-test-sources 
process-test-sources 
generate-test-resources 
process-test-resources 复制并处理资源文件,至目标测试目录。 
test-compile 编译测试源代码。 
process-test-classes 
test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。 
prepare-package 
package 接受编译好的代码,打包成可发布的格式,如 JAR 。 
pre-integration-test 
integration-test 
post-integration-test 
verify 
install 将包安装至本地仓库,以让其它项目依赖。 
deploy 将最终的包复制到远程的仓库,以让其它开发人员与项目共享。  

site生命周期

site生命周期的目的是建立发布项目站点,上面有项目的各种信息。

pre-site 执行一些需要在生成站点文档之前完成的工作 
site 生成项目的站点文档 
post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备 
site-deploy 将生成的站点文档部署到特定的服务器上  

Maven插件

我们前面说Maven的核心仅仅定义了抽象的生命周期,具体的任务是由插件完成的。为了让用户不用自己配置插件就能构建Maven项目,Maven在核心为一些主要的生命周期绑定了很多插件,当用户执行生命周期阶段时,对应的插件就会起作用。

自定义绑定插件

 <build>
        <plugins>
            <!--指定编译插件用的jdk版本-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
  </build>

插件的使用是Maven中很难的一个地方,如果需要深入可以去参考文档。

Maven聚合

在大型项目中,可能会有很多模块,在Maven中可以将这些模块给聚合成一个项目。

1.我们首先需要创建一个空的Maven项目,来去聚合其他模块,该模块的packaging必须为pom  
2.通过<module>标签聚合其他项目,该被聚合的项目路径必须放在聚合项目pom文件的同一路径下 

    <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/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.cad.MavenWeb</groupId>
      <artifactId>WebDemo</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>pom</packaging>
      <modules>
        <module>WebServlet</module>
        <module>WebService</module>
      </modules>
    </project> 

这里写图片描述

我们可以直接使用Eclipse图形化创建聚合项目
1.先创建一个Maven项目,将packaging改为pom
2.新建模块即可

这里写图片描述

这里写图片描述


3.我们执行一下编译命令,Maven会首先解析聚合模块的pom,分析需要构建的模块,然后根据顺序构建各个模块 

这里写图片描述

Maven继承

Maven的继承,实质上指的是pom文件的继承,我们在前面的例子中会发现,pom文件中有的时候会有很多重复的内容,例如重复引入插件,重复指定gav坐标等。

1.我们首先创建一个父项目,父项目的打包方式必须为pom
  由于父项目只是为了让子   项目继承pom文件,所以打包方式选为pom。

这里写图片描述

2.使用Eclipse创建子项目,只需要指定父项目的坐标即可 

这里写图片描述

我们看一下子项目的pom文件 ,可以看到用一个parent标签引入了父项目

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.cad.maven</groupId>
    <artifactId>ParentProject</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <groupId>com.cad.maven</groupId>
  <artifactId>ChildProject</artifactId>
  <version>0.0.1-SNAPSHOT</version>
</project>

依赖继承

子项目会默认继承父项目中的依赖。但是如果某个模块继承父项目,根本不需要这些依赖,怎么办?

Maven提供的<dependencyManagement> 标签既能让子模块继承父模块的依赖,也能保证子模块依赖使用的灵活性。<dependencyManagement> 下的依赖声明并不会引入实际的依赖,只是管理依赖的版本。 
例如 ,我们的父模块使用这个标签,这样即不会为父模块添加依赖,也不会为继承的子模块添加依赖  

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.cad.maven</groupId>
  <artifactId>ParentProject</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>

 <dependencyManagement>
   <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
 </dependencyManagement> 
</project>
我们的子模块的pom文件,我们只需要给出groupId,artifactId即可,版本继承父模块的,
简化了我们一些操作 

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.cad.maven</groupId>
    <artifactId>ParentProject</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <groupId>com.cad.maven</groupId>
  <artifactId>ChildProject</artifactId>
  <version>0.0.1-SNAPSHOT</version> 

   <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
   </dependencies>   
</project>

插件继承

同样的,Maven提供了<pluginManagement>来管理插件,和依赖继承一样,在这里面配置的插件并不存在实际的插件调用,等到子pom中配置了plugin元素时,才会真正调用。

使用Nexus创建私服

1.首先我们在官网下载Nexus, http://nexus.sonatype.org/
2.修改 \nexus-3.4.0-02\etc\nexus-default.properties文件,修改访问私服的地址和端口

这里写图片描述

3.我们在\nexus-3.4.0-02\bin 目录下执行窗口cmd命令,nexus.exe/run 
  执行成功后,即可访问    

这里写图片描述

4.我们输入 127.0.0.1:8081\即可访问私服 

这里写图片描述

5.默认的访问Nexus都是匿名的,匿名用户仅包含一些基本的权限,要全面学习Nexus,必须以管理员身份登录。
  Nexus管理员默认的账号密码是 admin/admin123

这里写图片描述

Nexus仓库和仓库组

Nexus包含了各种类型的仓库概念,包括代理仓库、宿主仓库、仓库组等,每一种仓库都提供了丰富实用的配置参数。

仓库有四种类型,group(仓库组),hosted(宿主),proxy(代理),virtual(虚拟)。仓库的格式为Maven2.仓库还有一个属性Policy(策略),表示该仓库是发布Release版本仓库还是Snapshot快照仓库。

这里写图片描述

Nexus内部的几种Maven仓库

1)maven-central:代理maven中央库,默认从https://repo1.maven.org/maven2/拉取jar 
2)maven-releases:一个策略为Release的宿主类型仓库,用来部署组织内部的发布版本构件
3)maven-snapshots:一个策略为Snapshot的宿主类型仓库,用来部署组织内部的快照版本构件
4)maven-public:仓库分组,把上面三个仓库组合在一起对外提供服务,在本地maven基础配置settings.xml中使用。 

Maven可以直接从宿主仓库下载依赖,Maven也可以从代理仓库中下载依赖,代理仓库会间接的从远程仓库下载依赖并缓存。仓库组只是一组仓库,它会转向其组内的仓库获取依赖。 

私服的配置可以自行百度,网上很多资料。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值