Maven插件

Maven插件

一、什么是生命周期  

    Maven的生命周期就是为了对所有的构建过程进行抽象和统一。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤
    几乎所有的项目构建都可以映射到这个生命周期上。每个构建步骤可以绑定一个或多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认插件。
    针对编译的插件有maven-compiler-plugin,针对测试的插件有maven-surefire-plugin
    Maven定义的生命周期和插件机制一方面保证了所有Maven项目有一致的构建标准,另一方面又通过默认插件简化和稳定了实际项目的构件,此外还提供了足够的扩展空间,用户可以通过
    配置现有插件或者自行编写插件来自定义构建行为

二、生命周期详解   

    maven拥有三套相互独立的生命周期,分别是clean、default、site,clean的目的是清理项目,default的目的是构建项目,site的目的是建立项目站点
    每个生命周期都有一些阶段,这些阶段是按顺序执行的,并且单独执行某个生命周期不会影响其他生命周期。
    clean生命周期:
    pre-clean:执行清理前需要完成的工作
    clean:清理上一次构建生成的文件
    post-clean:执行一些清理后需要完成的工作
    default生命周期:
    validate
    initialize
    generate-sources
    process-sources:处理项目主资源文件,一般来说,是对src/main/resources目录的内容进行变量替换等工作后,复制到项目输出的主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目录中
    process-test-classes
    test:使用单元测试框架运行测试,测试代码不会被打包或部署
    prepare-package
    package:接受编译好的代码,打包成可发布的格式,如JAR
    pre-integration-test
    integration-test
    post-integration-test
    verify
    install:将包安装到Maven本地仓库,供本地其他Maven项目使用
    deploy:将最终的包复制到远程仓库,供其他开发人员和Maven项目使用
    site生命周期:
    pre-site:执行一些在生成项目站点之前需要完成的工作
    site:生成项目站点
    post-site:执行一些在生成项目站点之后需要完成的工作
    site-deploy:将生成的项目站点发布到服务器上

三、命令行与生命周期 

    $mvn clean:调用clean生命周期的clean阶段,实际执行为clean生命周期的pre-clean、clean阶段
    $mvn test:调用default生命周期的test阶段,实际执行为default生命周期的validate、initialize等,直到test的所有阶段
    $mvn clean install: 调用clean生命周期的clean阶段、default生命周期的install阶段,实际执行clean生命周期的pre-clean、clean阶段以及default生命周期从validate至install的所有阶段
    $mvn clean deploy site-deploy:调用clean生命周期的clean阶段、default生命周期的deploy阶段以及site生命周期的site-deploy阶段,实际执行为clean生命周期的pre-clean、clean阶段,default生命周期的所有阶段,site生命周期的所有阶段

四、插件目标

    对于插件本身,为了代码的复用,往往可以完成多个任务,如果为每一个功能都编写一个插件显然是不可取的,那么就将这些功能都集中到一个插件中,那么这每个功能就叫做插件的目标,例如maven-dependency-plugin有十多个目标,每个目标

    对应一个功能,dependency:anlayze、dependency:tree、dependency:list。这是一种通用的写法,冒号前面是插件的前缀,冒号后面是插件的目标。

五、插件绑定

    Maven的生命周期与插件相互绑定,用以完成实际的构建任务。具体而言,是生命周期的阶段与插件目标相互绑定,以完成某个特定的构建任务。例如项目编译这一任务,它对应了default生命周期的compile这一阶段,而maven-compile-plufgin这

    一插件的conpile目标能够完成这项任务,因此,将它们绑定,就能实现项目的编译。

六、内置绑定

      为了能让用户几乎不用任何配置就能够使用Maven构建项目, Maven为一些主要的生命周期阶段绑定了很多插件,用户通过命令行调用生命周期阶段的时候,对应的目标就会执行相应的任务。如clean声明周期的clean目标,默认绑定maven-clean-plugin

    插件。用户可以执行mvn clean install命令,查看命令行输出,看项目构建过程中执行了哪些插件目标。

七、自定义绑定    

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

    例如创建项目的源码jar包,内置的插件绑定关系中是没有涉及这一任务的,此时需要用户自己配置,maven-source-plugin可以帮我们完成该任务,他的jar-no-fork目标能够将项目的主代码打包成jar文件,可以将其绑定到default生命周期的verify阶段

 1 <build>
 2     <plugins>
 3         <plugin>
 4             <groupId>org.apache.maven.plugins</groupId>
 5             <artifactId>maven-source-plugin</artifactId>
 6             <version>2.1.1</version>
 7             <executions>
 8                 <execution>
 9                     <id>attach-sources</id>
10                     <phase>verify</phase>
11                     <goals>
12                         <goal>jar-no-fork</goal>
13                     </goals>
14                 </execution>
15             </executions>
16         </plugin>
17     </plugins>
18 </build>                   

    执行mvn verify就能够在控制台看到如下信息:

    --- maven-source-plugin:2.1.1:jar-no-fork<attach-source>@HelloWorld -

    Building jar: E:\Workspace\HelloWorld\target\HelloWorld-sources.jar

      当插件目标被绑定到不同的生命周期阶段的时候,其执行顺序会由生命周期阶段的先后顺序决定,如果多个目标被绑定到同一阶段,这些插件声明的先后顺序决定了目标的执行顺序

八、插件配置

     1.命令行插件配置

        很多插件目标的参数都支持从命令行配置,用户可以在Maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件目标参数,例如,maven-surefire-plugin提供了一个maven.test.skip参数,当其值为true时,就会跳过执行测试。

        在命令行输入:mvn install -Dmaven.test.skip=true

        参数-D是java自带的,其功能是通过命令行设置一个Java系统属性,Maven简单的重用了该参数。

     2.POM中插件全局配置

        并不是所有的插件参数都适合从命令行配置,又下参数值从项目创建到项目发布都不会改变,对于这种情况,在POM中一次性配置显然比重复在命令行输入都要方便,用户可以在声明插件的时候,对此插件进行一个全局的配置。例如,我们通常会

        需要配置maven-compile-plugin告诉它编译Java 1.5版本的源文件,生成与JVM 1.5兼容的字节码文件    

 1 <build>
 2     <plugins>
 3         <plugin>
 4             <groupId>org.apache.maven.plugins</groupId>
 5             <artifactId>maven-compile-plugin</artifactId>
 6             <version>2.1</version>
 7             <configuration>
 8                 <source>1.5</source>
 9                 <target>1.5</target>
10             </configuration>
11         </plugin>        
12     </plugins>                       
13 </build>
14             

        这样,不管绑定到compile阶段的maven-compile-plugin:compile任务,还是绑定到test-compiler阶段的maven-compile-plugin:testCompiler任务,就都能够使用该配置,基于Java 1.5版本进行编译。

    3.POM中插件任务配置

        除了为插件配置全局的参数,用户还可以为某个插件任务配置特定的参数。例如,maven-autrun-plugin,它有一个目标run,可以用来在Maven中调用Ant任务。用户将maven-autrun-plugin:run绑定到多个生命周期阶段上,再加以不同的配置,

        就可以让maven在不同的生命阶段执行不同的任务

 1 <build>
 2     <plugins>
 3         <plugin>
 4             <groupId>org.apache.maven.plugins</groupId>
 5             <artifactId>maven-antrun-plugin</artifactId>
 6             <version>1.3</version>
 7             <executions>
 8                  <execution>
 9                       <id>ant-validate</id>
10                           <phase>validate</phase>
11                           <goals>
12                                <goal>run</goal> 
13                           </goals>  
14                           <configuration>
15                                 <tasks>
16                                     <echo>I`m bound to validate phase.</echo>
17                                 </tasks>   
18                           </configuration>
19                  </execution>
20                  <execution>
21                       <id>ant-verify</id>
22                           <phase>verify</phase>
23                           <goals>
24                                <goal>run</goal> 
25                           </goals>  
26                           <configuration>
27                                 <tasks>
28                                     <echo>I`m bound to verify phase.</echo>
29                                 </tasks>   
30                           </configuration>
31                  </execution>    
32             </executions>
33         </plugin>
34     </plugins>
35 </build>            

        这段代码中,首先maven-autrun-plugin:run与validate阶段绑定,从而构成一个id为ant-validate的任务,插件全局配置中configuration元素位于plugin元素下面,而这里的cinfiguration元素则位于execution元素下面,表示这是特定任务的

        配置,而非插件整体的配置,这个ant-validate任务配置了一个echo Ant任务,向命令行输出一段文字,表示该任务是绑定到validate阶段的。同样,第二个任务是绑定到verify阶段的,也向命令行输出一段文字,表示该任务绑定到verify阶段。

九、插件解析机制

     1.插件仓库

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

        Maven会区别对待依赖远程仓库和插件远程仓库,当Maven需要的依赖在本地仓库不存在时,它会去配置的远程仓库中查找,可是当Maven需要的插件在本地不存在时,它就不会去这些远程仓库中找。

        Maven的内置插件远程仓库: 

 1 <pluginRepositories>
 2     <pluginRepository>
 3         <id>central</id>
 4         <name>Maven Plugin Repository</name>
 5         <url>http://repo1.maven.org/maven2</url>
 6         <layout>default</layout>
 7         <snapshots>
 8             <enabled>false</enabled>
 9         </snapshots>
10         <releases>
11             <updatePolicy>never</updatePolicy>
12         </releases>
13     </pluginRepository>
14 </pluginRepositories>    

        一般情况下没中央仓库的插件完全能够满足我们的需要,只有在很少的情况下,项目的插件无法在中央仓库中找到,或者自己编写了插件,这个时候可以参考上述配置,在POM或settings.xml中加入其他插件仓库的配置。

    2.插件默认的groupId

        在配置POM的插件的时候,如果该插件是Maven官方插件,就可以省略groupId配置,如maven-compiler-plugin插件省略groupId时,Maven在解析的时候会自动默认groupId  org.apache.maven.plugins补齐。

    3.解析插件版本

        同样是为了简化插件的配置和使用,在用户没有提供插件版本的情况下,Maven会自动解析插件版本。

        首先,Maven在超级POM中为所有核心插件设定了版本,超级POM是所有Maven项目的父POM,所有项目都继承这个超级POM配置。如果用户使用的某个插件没有设定版本,而这个插件又不是核心插件,Maven会去检查所有仓库中的可用版本,

        然后做出选择。以maven-compiler-plugin为例,它在中央仓库的仓库元数据为http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml:

<metadata>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <versioning>
        <latest>2.1</latest>
        <release>2.1</release>
        <versions>
            <version>2.0-beta-1</verison>
            <version>2.0</verison>
            <version>2.0.1</verison>
            <version>2.0.2</verison>
            <version>2.1</verison>
        </versions>
        <lastUpdated>20100102092331</lastUpdated>
    </versioning>
</metadata>        

        Maven遍历本地仓库和所有远程插件仓库,将该路径下的仓库元数据归并后,就能计算出latest和release的值。latest表示仓库中该构件的最新版本,release表示最新的非快照版本。在Maven2中,插件会被解析至latest,而Maven3会解析到release

        依赖Maven解析插件版本其实是不推荐的做法,例如,可能某个插件发布了一个新版本,而这个版本的行为与之前的版本发生了变化,这种变化可能导致项目构建失败,因此,使用插件的时候,应该一直显式的设定版本。

    4.解析插件前缀

        插件前缀与groupId:artifactId是一一对应的,这种匹配关系存储在仓库元数据中。主要的插件都位于http://repo1.maven.org/maven2/org/apache/maven/plugins/和http://repository.codehaus.org/org/codehaus/mojo/,相应的,

        Maven在解析插件仓库元数据的时候会默认使用org.apache.maven.plugins和org.codehaus.mojo两个groupId。也可以通过配置settings.xml让Maven检查其他groupId上的插件仓库元数据

1 <settings>
2     <pluginGroups>
3         <pluginGroup>com.your.plugins</pluginGroup>
4     </pluginGroups>
5 </settings>

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

        下面看一下插件仓库元数据的内容:

 1 <metadata>
 2     <plugins>
 3         <plugin>
 4             <name>Maven Clean Plugin</name>
 5             <prefix>clean</prefix>
 6             <artifactId>maven-clean-plugin</artifactId>
 7         </plugin>
 8         <plugin>
 9             <name>Maven CompilerPlugin</name>
10             <prefix>compiler</prefix>
11             <artifactId>maven-compiler-plugin</artifactId>  
12         </plugin> 
13         <plugin>
14             <name>Maven DependencyPlugin</name>
15             <prefix>dependency</prefix>
16             <artifactId>maven-dependency-plugin</artifactId>
17         </plugin> 
18     </plugins>
19 </metadata>        

        从上述代码中可以看出,maven-clean-plugin插件的前缀为clean,maven-compiler-plugin插件的前缀为compiler,maven-dependency-plugin插件的前缀为dependency。

        当Maven解析到dependency:tree这样的命令后,它首先基于默认的groupId归并所有插件仓库的元数据org/apache/maven/plugins/maven-metadta.xml;其次检查归并后的元数据,找到对应的artifactId为maven-dependency-plugin;

        然后结合当前元数据的groupId org.apache.maven.plugins;最后解析得到version,这时就得到了完整的插件坐标。如果org/apache/maven/plugins/maven-metadta.xml没有记录该插件的前缀,则接着检查其他groupId下的元数据,如

        org/codehaus/mojo/maven-metadata.xml,以及用户自定义的插件组。如果所有元数据中都不包含该前缀,则报错。

 

posted on 2017-03-06 15:45  皮皮咚,我们走  阅读(749)  评论(1)    收藏  举报

导航