Maven第六讲 生命周期详解 高手必备!

时间:2022-07-25
本文章向大家介绍Maven第六讲 生命周期详解 高手必备!,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Maven第六讲

项目pom.xml中,有下面这样一段依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.2.1.RELEASE</version>
    </dependency>
</dependencies>

大家看一下上面的配置,有没有什么问题?

他们的groupId和version都是一样的,程序员面对与重复的代码,需要提取,如果是java代码中,我们可以将同样的代码或者变量值,提取成方法或者变量,做到重用,方便维护。

那么maven的pom.xml中也支持这么做:

<properties>
    <spring.group>org.springframework</spring.group>
    <spring.version>5.2.1.RELEASE</spring.version>
</properties>

<dependencies>
    <dependency>
        <groupId>${spring.group}</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>${spring.group}</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>${spring.group}</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
    </dependency>
</dependencies>

大家看一下上面的代码,properties位于pom.xml中的,是project元素的子元素,用户可以在properties中自定义一些用户属性,然后可以在其他地方使用${属性名称}这种方式进行引用。

生命周期

我们开发一个项目的时候,通常有这些环节:创建项目、编写代码、清理已编译的代码、编译代码、执行单元测试、打包、集成测试、验证、部署、生成站点等,这些环节组成了项目的生命周期,这些过程也叫做项目的构建过程,几乎所有的项目都由这些环节中的其中几个,创建项目和编写代码是我们程序员需要多参与的,其他的都可以做成自动化的方式。

用过ant的朋友回忆一下,在maven出现以前,开发人员每天都在对项目进行清理、编译、执行单元测试、打包、部署等操作,虽然大家都在做这些工作,但是没有一个统一的标准,项目和项目之间,公司和公司之间,大多数都是各写各的,写法是千奇百怪,能满足自身需求就可以了,但是换个项目就得从头再来,这些操作又需要重新编写脚本。

而maven出来之后,项目生命周期中的这些环节都被简化了,被规范化了,maven出现之前,项目的结构没有一个统一的标准,所以生命周期中各个环节对应的自动化脚本也是各种各样,而maven约定好了项目的结构,源码的位置、资源文件的位置、测试代码的位置、测试用到的资源文件的位置、静态资源的位置、打包之后文件的位置等,这些都是maven约定好的,所以清理代码用一个命令mvn clean就可以完成,不需要我们去配置清理的目标目录;用mvn compile命令就可以完成编译的操作;用mvn test就可以自动运行测试用例;用mvn package就可以将项目打包为jar、war格式的包,能够如此简单,主要还是maven中约定大于配置的结果。

maven中生命周期详解

maven将项目的生命周期抽象成了3套生命周期,每套生命周期又包含多个阶段,每套中具体包含哪些阶段是maven已经约定好的,但是每个阶段具体需要做什么,是用户可以自己指定的。

maven中定义的3套生命周期:

  1. clean生命周期
  2. default生命周期
  3. site生命周期

上面这3套生命周期是相互独立的,没有依赖关系的,而每套生命周期中有多个阶段,每套中的多个阶段是有先后顺序的,并且后面的阶段依赖于前面的阶段,而用户可以直接使用mvn命令来调用这些阶段去完成项目生命周期中具体的操作,命令是:

mvn 生命周期阶段

通俗点解释:

maven中的3套生命周期相当于maven定义了3个类来解决项目生命周期中需要的各种操作,每个类中有多个方法,这些方法就是指具体的阶段,方法名称就是阶段的名称,每个类的方法是有顺序的,当执行某个方法的时候,这个方法前面的方法也会执行。具体每个方法中需要执行什么,这个是通过插件的方式让用户去配置的,所以非常灵活。

用户执行mvn 阶段名称就相当于调用了具体的某个方法。

下面我们来看看每个生命周期中有哪些阶段(也就是我们说的每个类中有哪些方法,顺序是什么样的)。

clean生命周期

clean生命周期的目的是清理项目,它包含三个阶段:

生命周期阶段

描述

pre-clean

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

clean

移除所有上一次构建生成的文件

post-clean

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

用户可以通过mvn pre-clean来调用clean生命周期中的pre-clean阶段需要执行的操作。

调用mvn post-clean会执行上面3个阶段所有的操作,上文中有说过,每个生命周期中的后面的阶段会依赖于前面的阶段,当执行某个阶段的时候,会先执行其前面的阶段。

default生命周期

这个是maven主要的生命周期,主要被用于构建应用,包含了23个阶段。

生命周期阶段

描述

validate

校验:校验项目是否正确并且所有必要的信息可以完成项目的构建过程。

initialize

初始化:初始化构建状态,比如设置属性值。

generate-sources

生成源代码:生成包含在编译阶段中的任何源代码。

process-sources

处理源代码:处理源代码,比如说,过滤任意值。

generate-resources

生成资源文件:生成将会包含在项目包中的资源文件。

process-resources

编译:复制和处理资源到目标目录,为打包阶段最好准备。

compile

处理类文件:编译项目的源代码。

process-classes

处理类文件:处理编译生成的文件,比如说对Java class文件做字节码改善优化。

generate-test-sources

生成测试源代码:生成包含在编译阶段中的任何测试源代码。

process-test-sources

处理测试源代码:处理测试源代码,比如说,过滤任意值。

generate-test-resources

生成测试源文件:为测试创建资源文件。

process-test-resources

处理测试源文件:复制和处理测试资源到目标目录。

test-compile

编译测试源码:编译测试源代码到测试目标目录.

process-test-classes

处理测试类文件:处理测试源码编译生成的文件。

test

测试:使用合适的单元测试框架运行测试(Juint是其中之一)。

prepare-package

准备打包:在实际打包之前,执行任何的必要的操作为打包做准备。

package

打包:将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。

pre-integration-test

集成测试前:在执行集成测试前进行必要的动作。比如说,搭建需要的环境。

integration-test

集成测试:处理和部署项目到可以运行集成测试环境中。

post-integration-test

集成测试后:在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。

verify

验证:运行任意的检查来验证项目包有效且达到质量标准。

install

安装:安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。

deploy

部署:将最终的项目包复制到远程仓库中与其他开发者和项目共享。

site生命周期

site生命周期的目的是建立和发布项目站点,Maven能够基于pom.xml所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。主要包含以下4个阶段:

阶段

描述

pre-site

执行一些需要在生成站点文档之前完成的工作

site

生成项目的站点文档

post-site

执行一些需要在生成站点文档之后完成的工作,并且为部署做准备

site-deploy

将生成的站点文档部署到特定的服务器上

mvn命令和生命周期

从命令行执行maven任务的最主要方式就是调用maven生命周期的阶段,需要注意的是,每套生命周期是相互独立的,但是每套生命周期中阶段是有前后依赖关系的,执行某个的时候,会按序先执行其前面所有的。

mvn执行阶段的命令格式是:

mvn 阶段1 [阶段2] [阶段n]

多个阶段的名称之间用空格隔开。

下面我们举一些常见的例子来说明一下:

mvn clean 该命令是调用clean生命周期的clean阶段,实际执行的阶段为clean生命周期中的pre-clean和clean阶段。

mvn test 该命令调用default生命周期的test阶段,实际上会从default生命周期的第一个阶段(validate)开始执行一直到test阶段结束。这里面包含了代码的编译,运行测试用例。

mvn clean install 这个命令中执行了两个阶段:clean和install,从上面3个生命周期的阶段列表中找一下,可以看出clean位于clean生命周期的表格中,install位于default生命周期的表格中,所以这个命令会先从clean生命周期中的pre-clean阶段开始执行一直到clean生命周期的clean阶段;然后会继续从default生命周期的validate阶段开始执行一直到default生命周期的install阶段。

这里面包含了清理上次构建的结果,编译代码,测试,打包,将打好的包安装到本地仓库。

mvn clean deploy 这个命令也比较常用,会先按顺序执行clean生命周期的[pre-clean,clean]这个闭区间内所有的阶段,然后按序执行default生命周期的[validate,deploy]这个闭区间内的所有阶段(也就是default生命周期中的所有阶段)。这个命令内部包含了清理上次构建的结果、编译代码、运行单元测试、打包、将打好的包安装到本地仓库、将打好的包发布到私服仓库。

上面说了这么多理论,我们来看一下效果。

案例

创建一个maven项目

打开idea,点击File->New->Project,选择Maven,如下:

点击Next,输入项目坐标信息,如下:

点击Next,输入Project name 为maven-chat06,如下:

点击Finish,创建成功,如下:

配置一下idea的maven环境,点击File->Settings,如下图:

点击上面的OK完成配置。

还原~/.m2/settings.xml的配置到初始状态,操作如下:

将M2_HOME/conf/settings.xml复制到~/.m2/settings.xml目录,如果存在先备份一个,然后进行覆盖。

maven项目是约定大于配置的,项目结构是按照maven的约定生成好的,关于maven约定项目结构,我们再来回顾一下。

Maven 提倡使用一个共同的标准目录结构,Maven 使用约定优于配置的原则,大家尽可能的遵守这样的目录结构,如下所示:

结合刚才项目的结构和这个表格领会一下,下面我们来感受一下执行生命周期中的阶段产生的效果。

修改pom.xml,如下:

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javacode2018</groupId>
    <artifactId>maven-chat06</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 配置maven编译的时候采用的编译器版本 -->
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
        <!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->
        <maven.compiler.source>1.8</maven.compiler.source>
        <!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

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

</project>

上面properties这个元素中的配置,可能大家看不懂,先略过,后面会详解。

创建一个Demo类,源码是放在src/main/java目录中,如下:

package com.javacode2018.maven;

import java.util.ArrayList;
import java.util.List;

public class Demo1 {
    public static void main(String[] args) {
        System.out.println("欢迎你");
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            list.add(i);
        }
        list.forEach(System.out::print);
    }
}

mvn clean命令效果

在当前项目pom.xml所在目录中执行下面命令:

mvn clean

效果如下:

D:codeIdeaProjectsmaven-chat06>mvn clean
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.javacode2018:maven-chat06 >--------------------
[INFO] Building maven-chat06 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-chat06 ---
[INFO] Deleting D:codeIdeaProjectsmaven-chat06target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.477 s
[INFO] Finished at: 2019-11-15T18:46:13+08:00
[INFO] ------------------------------------------------------------------------

上面有提到编译、打包的内容都放在target目录,看上面输出中有个Deleting target目录,说明mvn clean是对这个目录进行清理,这个目录中目前是空的。

mvn compile命令效果

先看一下项目的目录中是没有target目录的,如下图:

cmd中执行:

mvn compile

输出:

D:codeIdeaProjectsmaven-chat06>mvn compile
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.javacode2018:maven-chat06 >--------------------
[INFO] Building maven-chat06 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-chat06 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-chat06 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:codeIdeaProjectsmaven-chat06targetclasses
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.897 s
[INFO] Finished at: 2019-11-15T18:53:12+08:00
[INFO] ------------------------------------------------------------------------

可以看到上面有Compiling 1 source …,这个是编译Demo.java,然后输出到了target中的classes目录,再来看一下项目的结构,如下图:

上图中匡红的是新生成的。

mvn clean package效果

D:codeIdeaProjectsmaven-chat06>mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.javacode2018:maven-chat06 >--------------------
[INFO] Building maven-chat06 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-chat06 ---
[INFO] Deleting D:codeIdeaProjectsmaven-chat06target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-chat06 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-chat06 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:codeIdeaProjectsmaven-chat06targetclasses
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-chat06 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-chat06 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-chat06 ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ maven-chat06 ---
[INFO] Building jar: D:codeIdeaProjectsmaven-chat06targetmaven-chat06-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.177 s
[INFO] Finished at: 2019-11-15T18:56:59+08:00
[INFO] ------------------------------------------------------------------------

从输出中看一下,有个Building jar …,生成了一个jar包,这个项目的pom.xml中的packaging元素没有指定值,那就取默认值jar,表示这个构件是一个jar包,mvn clean package先清理编译的代码,然后执行了default生命周期的compile阶段,将项目打成了jar放在了target目录,如下图:

大家看到上面还有很多其他的输出,这个大家可以先忽略,本文看完了,都会明白的。

mvn clean install效果

D:codeIdeaProjectsmaven-chat06>mvn clean install
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.javacode2018:maven-chat06 >--------------------
[INFO] Building maven-chat06 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-chat06 ---
[INFO] Deleting D:codeIdeaProjectsmaven-chat06target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-chat06 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-chat06 ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to D:codeIdeaProjectsmaven-chat06targetclasses
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-chat06 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-chat06 ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-chat06 ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ maven-chat06 ---
[INFO] Building jar: D:codeIdeaProjectsmaven-chat06targetmaven-chat06-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ maven-chat06 ---
[INFO] Installing D:codeIdeaProjectsmaven-chat06targetmaven-chat06-1.0-SNAPSHOT.jar to C:UsersThink.m2repositorycomjavacode2018maven-chat061.0-SNAPSHOTmaven-chat06-1.0-SNAPSHOT.jar
[INFO] Installing D:codeIdeaProjectsmaven-chat06pom.xml to C:UsersThink.m2repositorycomjavacode2018maven-chat061.0-SNAPSHOTmaven-chat06-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.977 s
[INFO] Finished at: 2019-11-15T19:05:21+08:00
[INFO] ------------------------------------------------------------------------

和mvn clean package的输出对比一下,多了几行输出,主要是多了2个Installing…,将项目打成jar包以及项目的pom文件放到本地仓库去了,也就是将构件打包安装到本地仓库了。

上面几个mvn命令的案例,都是通过mvn命令去执行了mvn中定义的生命周期中的阶段,然后完成了很多看似内部很复杂的操作。比如打包,内部包含很多复杂的操作,maven都帮我们屏蔽了,通过一个简单的mvn package就完成了。