Loading

Maven笔记 四 插件

先导

Maven笔记 三 仓库

问题

经过前几章的学习,好像对之前只会查询依赖,添加到pom里的Maven有了一些新的见解,但总好像还有一些疑问没有解开。

当我们想要编译代码的时候,我们会输入mvn clean compile,当我们想测试的时候,我们会输入mvn clean test。从字面理解,就是先去给我执行clean,再去给我执行compile或test。

下面是执行mvn clean compile的输出,看起来就是先执行了清理,然后对静态资源打包,然后编译。

有一个小小的疑问就是我们的命令行代码里并没有显式的指定对静态资源打包的动作,既然clean需要显式指明,那么执行三个操作的代码理应是mvn clean resources compile啊。先不管它,姑且认为打包资源文件是编译过程包含的操作,我们看mvn clean test的输出。

可以看到除了test外,前面那些也被执行了,但我们也没有指定compile这个动作啊,按理说,命令应该是mvn clean compile test。我们可不可以理解为,当我们执行后面的动作的时候,Maven会自动帮我们执行前面的动作??那clean岂不是可以省略??

执行一下mvn compile,结果如下

并没人帮我们做clean操作,这是为啥呢??好乱套!!

下面就解开这些疑问。

生命周期

Maven的生命周期有三个阶段,一个是clean,一个是default,一个是site。

clean

clean阶段就是用来清理之前的输出结果。又有三个子阶段。

  1. pre-clean 清理之前做的一些准备工作
  2. clean 清理工作
  3. post-clean 清理之后做的一些善后工作

注意,如果你在一个声明周期内执行,比如你执行post-clean,Maven会把这个生命周期中的之前的子阶段都执行了,在这个例子里也就是pre-cleanclean,因为一个生命周期中的后面的阶段依赖前面的阶段。

当然,Maven默认只提供了clean,所以我们看不到其它的两个,但其它的插件可以绑定到这两个生命周期上来。如何绑定,后面会说。

default

default阶段定义了构建过程中需要的所有步骤。

  1. validate
  2. initialize
  3. generate-sources
  4. process-sources 处理项目源代码,替换变量
  5. generate-resources
  6. process-resources
  7. compile 编译主项目代码,复制到项目输出的主classpath中
  8. process-classes
  9. generate-test-sources
  10. process-test-sources
  11. generate-test-resources
  12. process-test-resources
  13. test-compile 编译测试代码,复制到项目输出的测试classpath中
  14. process-test-classes
  15. test 进行单元测试
  16. prepare-package 准备打包
  17. package 打包编译好的代码为指定格式
  18. pre-integration-test 准备集成测试
  19. integration-test 进行集成测试
  20. post-integration-test
  21. verify
  22. install 安装项目到Maven本地仓库
  23. deploy 部署项目到远程仓库

有一些没有解释,但见到名字也都能差不多明白意思,需要注意,也是,当你执行这个生命周期阶段中的一个任务时,会把该生命周期之前的任务都执行。

现在就能解释了,为什么你测试时想要清理功能必须带上clean,而不用带上compile了吧,因为clean在另一个生命周期中,compile和test在一个生命周期,这样做的原因是测试有个前提是代码已经通过编译了,可以直接使用了,但之前的清没清理干净却不是一个硬前提。

site

主要生成项目的文档站点

  1. pre-site 预处理
  2. site 创建站点
  3. post-site 善后
  4. site-deploy 部署站点

生命周期的工作谁来执行?

现实编译工作太复杂了,可能每一个项目都有不同的编译过程,如果这些东西都给Maven实现,不太现实。所以Maven提供了插件机制,全世界的开发者根据各种需求来开发各种插件并公开出来,大家只需要去找对应的插件就行了,毕竟大部分我们遇到的问题,前人都已经解决。

所以Maven的生命周期中的每一个子步骤都绑定了插件,Maven只是针对其中的一些核心步骤提供了一些基本的插件而已。如编译绑定到了maven-compiler-plugin

若遇到没有绑定任何插件的子步骤,Maven会忽略这个步骤。

插件目标

嘶,我们也看到了,Maven的生命周期中有大量的子阶段,尤其是在default中。

那难道每个步骤都得开发一个插件吗,还是看之前的输出。

我们注意到,处理主项目资源和测试资源的都是maven-resources-plugin,而处理主项目代码和处理编译代码的都是maven-compiler-plugin,因为这些操作基本都是一样的,只是输出的路径不一样,为之再编写一个插件,有点小题大做。

那Maven如何处理这个问题呢?就是引入插件目标,一个插件可以有若干个目标。比如下面这个maven-resources-plugin版本号后面的冒号后面的resource就是这个插件的一个目标。和Maven生命周期绑定的实际是这个插件目标,这个目标做了打包主项目的资源,输出到主项目的classpath的工作。

而对于测试资源,又有一个目标叫testResources

这样就做到了让这些基本没区别的代码复用在一个插件中。

插件绑定

再重复一遍,与生命周期中具体步骤绑定的是插件的目标。如下图,default生命周期中的compile阶段与maven-compiler-plugin的compile目标绑定。

下面是clean和site中的阶段默认绑定的插件目标

下面是default中的阶段默认绑定的插件目标

自定义绑定

我们还可以自己去配置其它的插件甚至自己编写插件绑定到这些生命周期阶段中。

比如我们想生成项目的源码jar包,可以使用maven-source-pluginjar-no-fork目标。

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>2.4</version>
        <executions>
            <execution>
                <id>attach-sources</id>
                <phase>verify</phase>
                <goals>
                    <goal>jar-no-fork</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

上面的代码把这个插件的jar-no-fork目标绑定到了default中的verify阶段。

运行mvn clean verify

上面的图我就没截全,不过可以看到这个目标已经作用了,并生成了源码文件。

一些插件的目标会提供默认的阶段,比如你删掉上面的phase标签,再次执行mvn clean verify,这个目也执行了。

maven-help-plugin可以查看插件的具体信息。

插件配置

每一个插件可以有一些参数,可以通过命令行和POM配置

命令行配置

使用-Dxxx=xxx可以配置插件参数

例如maven-help-plugin可以指定-Dplugin参数来设置要获取帮助的插件。

mvn help:describe -Dplugin = org.apache.maven.plugins:maven-source-plugin

POM配置

像help这类插件适合使用命令行配置,因为每次的参数可能不一致,而且很少一致,但有些插件的参数基本不会变,那么每次都用冗长的命令行,太烦了。

可以使用configuration来配置参数

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
    <archive>
        <manifest>
            <addClasspath>true</addClasspath>
            <classpathPrefix>lib/</classpathPrefix>
            <mainClass>io.lilpig.hellomvn.helloworld.HelloWorld</mainClass>
        </manifest>
    </archive>
</configuration>

配置也可以绑定在不同的生命周期阶段上,只要写在excutions中即可。

插件解析

插件和依赖一样,用到先去本地仓库找,找不到去远端仓库,但是插件和依赖不使用同一个仓库配置。

需要使用pluginRepositories标签配置插件仓库

除了头两个标签不一样,其余的和依赖的配置语法一致。

groupId

插件的GroupId可以省略,如果省略会用Maven默认的groupId补充,org.apache.maven.plugins。不推荐。

version

为了简化插件使用,用户可以不配置插件版本,maven在超级POM中(所有项目pom文件的父文件)为所有核心插件设置了版本。如果用户不指定就会默认使用设定好的版本。

对于第三方插件Maven会自动获取仓库中插件的元数据信息maven-metadata.xml

这个文件说明了当前最新的版本和最新的稳定版,最新版本可能是快照版。

Maven2的默认做法是当一个第三方插件没指定版本时,使用latest中的版本,Maven3是使用release中的版本。

不论如何,不应该不指定插件的值。

posted @ 2021-08-30 21:00  yudoge  阅读(114)  评论(0编辑  收藏  举报