1、Maven的生命周期
Maven的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。Maven有三套相互独立的生命周期,分别是clean、default和site。其中每个生命周期都包含一些阶段(phase),阶段是按顺序执行的,且后面的阶段依赖于前面的阶段。执行某个阶段时,其前面的阶段会依顺序执行,但不会触发另外两套生命周期中的任何阶段。
Maven的三套生命周期:
- clean生命周期(项目清理生命周期):对在进行构建之前进行的一些清理工作。clean
- default生命周期(默认生命周期):构建的核心部分,编译、测试、打包、安装、部署等等。compile test install package
- site生命周期(生成站点生命周期):生成项目报告,站点,发布站点。site
注意:由于这三个阶段的生命周期都是相互独立的,所以不能看成一个整体。但可以同时直接运行 mvn clean install site 这三套生命周期。下面我们分别来谈谈这三个生命周期。
因为Maven的生命周期是抽象的,所以生命周期不做任何实际的工作,实际任务由插件来完成。
2、Clean生命周期(Clean Lifecycle)
Clean Lifecycle 对在进行构建之前进行的一些清理工作。
Clean生命周期一共包含了三个阶段:
- pre-clean:执行一些需要在clean之前完成的工作
- clean:移除所有上一次构建生成的文件
- post-clean:执行一些需要在clean之后立刻完成的工作
3、Default生命周期(Default Lifecycle)
Default Lifecycle是构建的核心部分,编译,测试,打包,部署等等,Default生命周期是Maven生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。
其中一些比较重要和常用的阶段:
- validate:验证项目的正确性。
- initialize:初始化构建状态,比如设置属性值。
- 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 ,WAR。
- pre-integration-test:执行集成测试之前的准备工作。
- integration-test:集成测试。
- post-integration-test:集成测试后继续操作。
- verify:检查包是否有效。
- install:将包安装至本地仓库,以让其它项目依赖。
- deploy:将最终的包复制到远程的仓库,以让其它开发人员与项目共享。
注意:在一个生命周期中,当运行某个阶段的时候,它之前的所有阶段都会被运行,而且不需要额外去输入前面的阶段。下面举例说明一下:
①、执行mvn clean:调用clean生命周期的clean阶段,实际执行pre-clean和clean阶段。
②、执行mvn test:调用default生命周期的test阶段,实际执行test以及之前所有阶段。
③、执行mvn clean install:调用clean生命周期的clean阶段和default的install阶段,实际执行pre-clean和clean,install以及之前所有阶段。
然后下面举第②个例子:执行mvn test。
在IDEA中执行test命令:
前面说了Maven的命令是有各自对应的插件去完成。我们看到红色框的部分,有三个不同类型的Plugin。第一个maven-resources-plugin:3.0.2是用来处理资源文件的,第二个maven-compiler-plugin:3.8.0是用来编译文件的。第三个maven-surefire-plugin:2.22.1是用来测试文件的。它们的具体会在后面介绍。
4、Site生命周期(Site Lifecycle)
Site Lifecycle 生成项目报告,站点,发布站点,站点的文档(站点信息,依赖..)。
Site生命周期,生成站点信息四个阶段:
pre-site:执行一些需要在生成站点文档之前完成的工作
site:生成项目的站点文档
post-site:执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
site-deploy:将生成的站点文档部署到特定的服务器上
这里经常用到的是 site 阶段和 site-deploy 阶段,用来生成和发布 maven 站点,这是 Maven 比较强大的功能,文档及统计数据自动生成。由于现在的系统会有专门工具来生成文档或报表。所以这个功能也是比较鸡肋吧,不够简洁和美观,用的不太多。
5、Maven中常用命令
通过上面对maven的生命周期的分析,可以总结出maven中常用的命令有:clean、compile、test、package、install。所以下面我们讲讲这几个常用的 Maven 命令。首先我们先创建一个Maven项目。并且在里面添加一些代码用来测试。
在 src/main/java新建类 HelloMaven.java:
package com.thr; /** * @author tanghaorong * @date 2020-06-09 * @desc 主代码 */ public class HelloMaven { public String hello(String name){ return name; } }
在 src/test/java新建中创建测试类 TestMaven.java
package com.thr; import org.junit.Assert; import org.junit.Test; /** * @author tanghaorong * @date 2020-06-09 * @desc 测试代码 */ public class TestMaven { @Test public void testHello(){ HelloMaven helloMaven = new HelloMaven(); String name = helloMaven.hello("唐浩荣"); //比较输入参数是否同 Assert.assertEquals("唐浩荣",name); } }
pom.xml 文件引入JUnit依赖如下:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies>
①、clean:将之前编译的文件删除。
我们首先运行一下程序,让它生成target文件。
然后再运行clean命令。在IDEA的右侧栏找到Maven Projects(如果没有则在菜单栏找到View—>第一行Tool Windows—>Maven Projects)。
双击clean命令。
这时,控制台打印输出:
这时,再看一下工作空间,target文件夹被删除了。
②、compile:编译项目,并将编译的文件放在target目录。
双击compile命令。这时,控制台打印输出:
再看一下工作空间,生成了 target文件夹。
点击 target文件夹, 不仅仅有 classes文件夹,里面放置 包名/HelloMaven.class ,还生成了其他的文件夹。
③、test:使用单元测试框架运行测试代码。
双击test命令。这时,控制台打印输出:
再看一下工作空间,target 除了刚才的那些文件夹之外,又添加了几个。 test-classes,,里面放置了 包名/HelloTest.class。
④、package:对项目进行打包,放在target目录中。
双击package命令。这时,控制台打印输出:
再看一下工作空间,target 除了刚才的那些文件夹之外,又多了一个 项目名-版本-快照.jar包。
⑤、install:将包安装至本地仓库,以让其它项目依赖。
双击install命令。这时,控制台打印输出:
再看一下工作空间,target 相对于package来说,没有任何改变。 改变的是本地仓库。根据红框的地址找到我们安装的jar包:D:\Maven\maven-repository\com\thr\hellomaven\1.0-SNAPSHOT。里面有 jar包和相应的 pom.xml 文件,只是pom.xmlde 名称变成了 jar包名.pom。
6、Maven插件介绍
我们知道,Maven生命周期是依靠各种插件来完成的,而我们打开Maven的源文件并没有发现有plugin,这是因为我们在第一次使用Maven的时候它会给我们自动下载,还记得在第一次配置并且运行Maven项目的时候,加载的时间有点长,输出界面也一直在下载东西,此时就在下载我们的插件。所以我们是可以找的下载的插件的,定位到:%本地仓库%\org\apache\maven\plugins,可以看到一些下载好的插件:
①、插件的目标(Plugin Goals)
一个插件通常可以完成多个任务,每一个任务就叫做插件的一个目标。如执行mvn compile命令时,此时的 compile 就是一个目标,调用的插件和执行的插件目标如下:
每个插件都有哪些个目标,官方文档有更详细的说明:Maven Plugins。
②、插件如何与生命周期进行绑定?
插件与生命周期绑定是通过将插件的目标(goal)绑定到生命周期的具体阶段(phase)来完成的。如:将maven-compiler-plugin插件的compile目标绑定到default生命周期的compile阶段,完成项目的源代码编译:
③、内置的绑定
Maven对一些生命周期的阶段(phase)默认绑定了插件目标,因为不同的项目有jar、war、pom等不同的打包方式,因此对应的有不同的绑定关系,其中针对default生命周期的jar包打包方式的绑定关系如下:
名称 | 阶段 | 插件:目标 |
生成资源 | generate-resources | plugin:descriptor |
处理资源 | process-resources | resources:resources |
编译 | compile | compiler:compile |
处理测试编资源 | process-test-resources | resources:testResources |
测试编译 | test-compile | compiler:testCompile |
测试 | test | surefire:test |
打包 | package | jar:jar |
安装 | install | install:install |
部署 | deploy | deploy:deploy |
第三列中【插件:目标】,其中冒号后面即是绑定的插件目标,冒号前面是插件的前缀(prefix),是配置和使用插件的一种简化方式。详细可查看Maven官方文档:Plugin Prefix。
④、自定义绑定
用户可以根据需要将任何插件目标绑定到任何生命周期的阶段,如:将maven-source-plugin的jar-no-fork目标绑定到default生命周期的package阶段,这样,以后在执行mvn package命令打包项目时,在package阶段之后会执行源代码打包。
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.2.1</version> <executions> <execution> <id>attach-source</id> <phase>package</phase><!-- 要绑定到的生命周期的阶段 --> <goals> <goal>jar-no-fork</goal><!-- 要绑定的插件的目标 --> </goals> </execution> </executions> </plugin> </plugins> …… </build>
在<plugin>插件元素中,<execution>元素是执行目标,<phase>元素代表的是绑定的生命周期的阶段,<goal>元素代表要绑定的插件的目标。 插件是前面artifactId中定义好的,goals相当于该插件中的一个功能,该功能将在phase绑定的生命周期阶段执行。这种方式就属于自定义绑定,即在某个特定的生命周期阶段执行某个插件的功能,此时大多数时候是内置绑定的。
⑤、配置插件
Maven插件高度易扩展,可以方便的进行自定义配置。如:配置maven-compiler-plugin插件编译源代码的JDK版本为1.7:
<!-- 编译插件 --> <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>
- source: 源代码编译版本;
- target: 目标平台编译版本;
- encoding: 字符集编码。