Maven 学习总结 (二) 之 生命周期与插件

时间:2023-03-08 19:49:44
Maven 学习总结 (二) 之  生命周期与插件

五、生命周期与插件

  1、Maven有三套独立的生命周期:clean、default和site。 clean生命周期的目的是清理项目,default生命周期的目的是构建项目,site生命周期的目的是建立项目站点。

clean生命周期:pre-clean、clean、post-clean

default生命周期:validate、initialize、generate-sources、process-sources(处理项目主资源文件,对src/main/rescources目录内容进行变量替换等工作后,复制到项目输出的主classpath)、

        generate-resources、process-resources、compile(编译项目的主源码,编译src/main/java目录下的Java文件至项目输出的主classpath目录中。)process-classes、

        generate-test-sources、process-test-sources(处理项目测试资源文件,对src/test/resources目录的内容进行变量替换等工作后,复制到项目输出的测试classpath目录中。)

        generate-test-resources、 process-test-resources、test-compile(编译项目的测试代码,是编译src/test/java目录下的Java文件至项目的测试classpath目录中)、test、

        prepare-package、package(接受编译好的代码,打包成可发布的格式)、pre-integration-test、integration-test、post-integration-test、verify、install(将包安装到maven

        本地仓库,供其他人和项目使用)、deploy(将最终的包复制到远程仓库,供其他开发人员和项目使用)

site生命周期:pre-site、site(生成项目站点文档)、post-site、site-deploy(将生成的站点发布到服务器上)。

  2、命令行与生命周期

  从命令行执行maven任务的最主要方式就是调用maven的生命周期阶段。

  mvn clean 调用clean生命周期的clean阶段。

  mvn test 调用default生命周期的test阶段。

  mvn clean install 调用clean生命周期的clean阶段和defaulte生命周期的install阶段。

  mvn clean deploy site-deploy 调用clean的阶段、default生命周期的deploy阶段,以及site生命周期的site-deploy阶段。

maven中主要的生命周期阶段并不多,而常用的maven命令实际是基于这些阶段简单组合而成的。

  3、插件目标

  maven的核心仅仅定义了抽象的生命周期,具体的任务是交由插件完成的,插件以独立的构件形式存在。

  maven的生命周期与插件相互绑定,用以完成实际的构建任务。具体讲是生命周期的阶段与插件的目标相互绑定,以完成某个具体构建任务。

    Maven 学习总结 (二) 之  生命周期与插件

  为了能让用户几乎不用任何配置就能构建maven项目,maven在核心为一些主要的生命周期阶段绑定了很多插件目标,当用户通过命令调用生命周期阶段的时候,对应的插件

   目标就会执行相应的任务。

   clean生命周期的pre-clean、clean和post-clean三个阶段,只有clean与maven-clean-plugin:clean绑定。maven-clean-plugin仅有clean这一个目标,其作用是删除项目输出目录。

   site生命周期的pre-site、site、post-site和site-deploy四个阶段,其中,site和maven-site-plugin:site相互绑定,maven-site-plugin有很多目标,其中site目标用来生成项目站点,

deploy目标用来将项目站点部署到远程服务器上。

Maven 学习总结 (二) 之  生命周期与插件

   default生命周期与插件目标的绑定关系就显得复杂些。这是因为对于任何项目来说,例如jar项目和war项目,他们的项目清理和站点生成是一样的,不过构建过程会有区别。

例如jar项目需要打包成JAR包,而war项目需要打成WAR包。由于项目的打包类型会影响构建的具体过程,因此,default生命周期的阶段与插件目标的绑定关系由项目打

   包类型所决定,打包类型是通过POM中的packaging元素定义的。基于打包类型是jar的项目,其default生命周期内置插件绑定关系及具体任务如表:

    Maven 学习总结 (二) 之  生命周期与插件

  default生命周期还有很多其他阶段,默认他们没有绑定任何插件,因此也没有任何实际行为。

  4、自定义绑定

 

     除了内置绑定以外,用户还能够自己选择某个插件目标绑定到生命周期的某个阶段上,这种自定义绑定方式能让maven项目在构建过程中执行更多更富特色的任务。

  <build>

    <plugins>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-source-plugin</artifactId>

        <version>2.1.1</version>

        <executions>

          <execution>

            <id>attched-sources</id>

            <phase>verify</phase>

            <goals>

              <goal>jar-no-fork</goal>

            </goals>

           </execution>

        </executions>

      </plugin>

    </plugins>

   </build>

  

在POM的build元素下的plugins子元素中声明插件的使用,该例中用到的是maven-source-plugin,其中groupId为org.apahe.maven.plugins,这是maven官方插件的groupId。

     对于自定义绑定的插件,用户总是应该声明一个非快照版本,这样可以避免由于插件版本变化造成的构建不稳定性。除了基本插件坐标声明外,还有插件执行配置,

executions下每个execution子元素可以用来配置执行一个任务。该例中配置一个id为attch-sources的任务,通过phase配置,将其绑定到verify生命周期阶段上,再通过goals

   配置指定要执行的插件目标。

     有时候,即使不通过phase元素配置声明周期阶段,插件目标也能够绑定到生命周期中去。原因是,很多插件的目标在编写时已经定义了默认绑定阶段。

   可以使用maven-help-plugin 查看插件详细信息,了解插件目标的默认绑定阶段。

 

  5、插件配置

  完成了插件和生命周期的绑定之后,用户还可以配置插件目标的参数,进一步调整插件目标所执行的任务,以满足项目的需求。

  命令行配置

    在日常maven使用中,我们经常从命令行输入并执行maven命令。这种情况下,能够方便地改变某些插件的行为十分方便。 用户可以在maven命令中使用-D参数,

并伴随一个参数健=参数值的形式,来配置插件目标的参数。

$ mvn install-Dmaven.test.skip=true,参数-D是java自带的,其功能是通过命令行设置一个java系统属性,maven简单第重用了该参数,在准备插件的时候检查系统属性,

    便实现了插件参数的配置。

   全局配置:

     并不是所有的插件参数都适合从命令行配置,有些参数的值从项目创建到项目发布都不会改变,或者说很少改变,对于这种情况,POM文件中一次性配置就显然比重复在

   命令行输入要方便。

  <build>

    <plugins>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-compiler-plugin</artifactId> 

        <version>2.1</version>

        <configuration>

          <source>1.5</source>

          <target>1.5</target>

        </configuration>

      </plugin>

    </plugins>

  </build>

   这样,不管绑定到compile阶段的maven-compiler-plugin:compile任务,还是绑定到test-compiler阶段的maven-compiler-plugin:testCompiler任务,就能够使用该配置,

   基于java1.5版本进行编译。

  POM中插件任务配置:

   除了为插件配置全局参数,用户还可以为某个插件任务配置特定参数,以maven-antrun-plugin,他有一个目标run,可以用来在maven中调用Ant任务。

   用户将maven-antrun-plugin:run绑定到多个生命周期阶段上,再加以不同的配置,就可以让maven在不同的生命阶段执行不同的任务。

  <build>

    <plugins>

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-antrun-plugin</artifactId>

        <version>1.3</version>

        <executions>

          <execution>

            <id>ant-validate</id>

            <phase>validate</phase>

            <goals>

              <goal>run</goal>

            </goals>

            <configuration>

              <tasks>

                <echo>I am bound to validate phase.</echo>

              </tasks>

            </configuration>

          </execution>

          <execution>

            <id>ant-verify</id>

            <phase>verify</phase>

            <goals>

              <goal>run</goal>

            </goals>

            <configuration>

              <tasks>

                <echo>I am bound to verify phase.</echo>

              </tasks>

            </configuration>

          </execution>

        </executions>

      </plugin>

    </plugins>

  </build>

  上述代码片段中,首先maven-antrun-plugin:run与validate阶段绑定,从而构成一个id为ant-validate的任务。插件全局配置中的configuration元素位于plugin元素下面,

而这里的configuration元素则位于execution元素下,表示这是特定任务的配置,而非插件整体的配置。这个ant-validate任务配置了一个echo ant任务,

  向命令行输出一段文字,表示该任务是绑定到validate阶段的。第二 个任务的id为ant-verify,它绑定到了verify阶段,同样她输出一段文字到命令行,

  告诉该任务绑定到了verify阶段。

  获取插件信息:

  插件信息:基本上所有主要的maven插件都来自apache和Codeaus。

  maven-help-plugin描述插件:除了访问在线的插件文档之外,还可以借助maven-help-plugin来获取插件信息。

  从命令行调用插件

  如果在命令行运行mvn-h来显示mvn命令帮助,就可以看到如下信息

  usage:mvn [optiona] [<goal(s)>] [phase(s)]

  options:

  ...

  该信息高速我们mvn命令基本用法,options表示可用的选项,mvn命令有20多个选项,这里暂不详述。命令后面可以添加一个或者多个goal和phase,

  他们分别指插件目标和生命周期阶段。可以通过mvn命令激活生命周期阶段,从而执行那些绑定在生命周期阶段上的插件目标。但maven还支持直接从命令行调用插件目标。

  支持这种方式是因为有些任务不适合绑定生命周期上。

  

  6、插件解析机制

  

  为了方便用户使用和配置插件,Maven不需要用户提供完整的插件坐标信息,就可以解析到正确的插件,这样虽然简化了插件的使用和配置,可一旦插件的行为出现异常,

  用户就很难快速定位到问题的插件构件。例如mvn help : system这样一条命令,到底执行了什么插件,该插件的groupId、artifactId和version分别是什么?

  插件仓库:与依赖构件一样,插件构件同样基于坐标存储在maven仓库中。在需要的时候,maven会从本地仓库寻找插件,如果不存在,则从远程仓库查找。找到插件之后,

  再下载到本地仓库使用。mave会区别对待依赖的远程仓库与插件仓库。当maven需要的依赖在本地仓库不存在时,它会去所配置的远程仓库查找,可是当maven需要的插件

  在本地仓库不存在时,它就不会去这些远程仓库查找。插件的远程仓库使用pluginRepositories和pluginRepository配置。内置的插件远程仓库配置 如下。

  这个默认插件仓库的地址就是*仓库.

  Maven 学习总结 (二) 之  生命周期与插件

  项目使用的插件无法在*仓库找到,或者自己编写了插件,这个时候可以参考以上的配置,在POM或者settings.xml中加入其它的插件仓库配置。

  插件的默认groupId:在POM中配置插件的时候,如果该插件是maven的官方插件,可以省略groupId配置。

  解析插件版本:同样是为了简化插件配置和使用,在用户没有提供插件版本的情况下,maven会自动解析插件版本。maven在超级pom中为所有核心插件设定了版本,

  超级pom是所有maven项目的父pom。所有项目都继承这个超级pom的配置,因此即使用户不加任何配置,maven使用核心插件的时候,他们的版本都就已经确定了,

  这些插件包括maven-clean-plugin、maven-compiler-plugin、maven-surefire-plugin等。

  如果用户使用某个插件时没有设定版本,而这个插件不属于核心插件的范畴,maven就会去检查所有仓库中可用的版本,然后做出选择。

  以maven-compiler-plugin为例,在*仓库的仓库元数据为http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml

  内容如下:

  Maven 学习总结 (二) 之  生命周期与插件

  maven遍历本地仓库和所有远程插件仓库,将该路径下的仓库元数据归并后,就能计算出latest和release的值。latest表示所有仓库中该构建的最新版本,而release表示最新的非快照版本。

  解析插件前缀:mvn命令行支持使用插件前缀来简化插件调用,现在解释maven如何根据插件前缀解析到插件的坐标。插件前缀与groupId:artifactId是一一对应的,

  这种匹配关系存在仓库元数据中,仓库元数据为groupId/maven-metadata.xml。maven解析插件仓库元数据的时候,会默认使用org.apache.maven.plugins和

  org.codehaus.mojo两个groupId.可以通过配置settings.xml让maven检查其他groupId是哪个的插件仓库元数据:

  Maven 学习总结 (二) 之  生命周期与插件

  基于该配置,maven就不仅仅会检查org/apache/maven/plugins/maven-metadata.xml和org/codehaus/mojo/maven-metadata.xml还会检查com/your/plugins/maven-metadata.xml

  Maven 学习总结 (二) 之  生命周期与插件

  上述内容是从*仓库的org.apache.maven.plugins groupId下插件仓库元数据中截取的一些片段,从这段数据中就能看到maven-clean-plugin的前缀为clean,maven-compiler-plugin的

  前缀为compiler,maven-dependency-plugin的前缀为dependency.

  当maven解析到denpendency:tree这样的命令后,他首先基于默认的groupId归并所有插件仓库的元数据org/apache/maven/plugins/maven-metadata.xml.其次检查归并后的元数据,

  找到对应的artifactId为maven-dependency-plugin,然后结合当前元数据的groupId找到对应的artifactId为maven-dependency-plugin然后结合当前元数据的groupI org.apache.maven.plugins.

  解析到version,这是就得到了完整的插件坐标。