• Maven内部运行原理


    maven至今还是Java编程语言构建的事实标准,大部分项目还在使用maven来进行构建,因此了解maven内部运行的原理对定位和分析问题还是很有裨益的。本篇文章主要介绍一些maven内部运行过程中的一些基本概念,相信看完后,对那么些刚刚接触maven的读者来说maven将不再陌生。
      在具体分析项目构建的过程前,需要了解maven的一些基本概念,这些概念十分重要,请务必理解清楚后再看下文。基本概念主要有:POM,Lifecycle。这两个概念又会包含一些小的概念,下文会逐步讲解。
      POM: 注意这里的POM不是maven中构建过程使用的配置文件pom.xml,但他们之间还是有联系的。POM的全称是Project Object Model,用通俗点的话说就是对要构建的项目进行建模,将要构建的项目看成是一个对象(Object),后文就使用PO来指代这个对象。既然是一个对象,那么PO有哪些属性呢?在maven中一个项目都是用一个唯一的坐标(coordinate)来表示,坐标由groupId, artifactId, version, classifier, type这五部分组成。这样来说PO应该也要具备坐标属性。另外一方面,一个项目肯定不是孤立存在的,可能依赖于其他的一些项目,那么也就是说PO应该具备dependencies这个属性,用来表示其所依赖的外部项目。我们可以尝试一下用Java代码来描述下PO这个对象:
    class PO{ 
        private String groupId;
        private String artifactId; 
        private String version; 
        private String classifier; 
        private String type; 
        private Set<PO> dependencies; 
    }
    

    我们知道XML的表达能力是很强大的,一个Java中的对象是可以用XML来描述,例如一个上面定义的PO对象则可以用下面的XML来描述(表达有不规范之处,理解其中的含义即可):

    <PO> 
        <groupId></groupId> 
        <artifactId></artifactId> 
        <version></version> 
        <classifier><classifier> 
        <type></type> 
        <dependencies> 
            <PO></PO> <PO></PO> ... 
        </dependencies> 
    </PO>
    是不是好像和什么有点类似?对,就是pom.xml。pom.xml就是PO对象的XML描述。上面的PO定义还不完整,我们继续看下PO还有什么其他的属性。我们知道在Java中类是可以继承的,一个对象在创建的时候会同时创建其父类对象,类似的,PO对象也有其父对象,用parent属性来表示,并且PO对象会继承其父对象的所有属性。另外一方面,一个项目可能根据不同职责分为多个模块(module),所有模块其实也就是一个单独的项目,只不过这些项目会使用其父对象的一些属性来进行构建。我们将这些新的属性加到PO的定义中去:
    class PO{ 
        private String groupId; 
        private String artifactId; 
        private String version; 
        private String classifier; 
        private String type; 
        private Set<PO> dependencies; 
        private PO parent; 
        private Set<PO> modules; 
    }
    

    再将这个定义用XML语言表示一下:

    <PO>
        <parent></parent>
        <groupId></groupId>
        <artifactId></artifactId>
        <version></version>
        <classifier><classifier>
        <type></type>
        <dependencies>
            <PO></PO> <PO></PO> ...
        </dependencies>
        <modules> ... </modules>
    </PO>

    是不是越来越像pom.xml了?对,这就是pom.xml的由来。再说一遍:pom.xml就是PO对象的XML描述。到此为止,相信你再看pom.xml文件时,会有一个全新的认识。

      上面说的这些PO属性是项目的一些固有属性,到目前为止,我们还没有涉及项目的构建过程。构建过程对应的是PO对象的build属性,那么你应该马上想到,在pom.xml中就是<build>元素中的内容。这里就有引入maven中第二个核心概念:Lifecycle。Lifecycle直译过来就是生命周期。我们平常会接触到哪些周期呢?一年中春夏秋冬就是一个周期。一个周期中可能分为多个阶段,比如这里的春夏秋冬。在maven中一个构建过程就对应一个Lifecycle,这个Lifecycle也分为多个阶段,每个阶段叫做phase。你可能会问,那这个Lifecycle中包含多少个phase呢?一个标准的构建Lifecycle包含了如下的phase:

    validate: 用于验证项目的有效性和其项目所需要的内容是否具备 
    initialize:初始化操作,比如创建一些构建所需要的目录等。 
    generate-sources:用于生成一些源代码,这些源代码在compile phase中需要使用到 
    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:打包 
    pre-integration-test:集成测试前置操作 
    integration-test:集成测试 
    post-integration-test:集成测试后置操作 
    install:将打包产物安装到本地maven仓库 
    deploy:将打包产物安装到远程仓库
    在maven中,你执行任何一个phase时,maven会将其之前的phase都执行。例如 mvn install,那么maven会将deploy之外的所有phase按照他们出现的顺序一次执行。
      Lifecycle还牵涉到另外一个非常重要的概念:goal。注意上面Lifecycle的定义,也就是说maven为程序的构建定义了一套规范流程:第一步需要validate,第二步需要initialize... ... compile,test,package,... ... install,deploy,但是并没有定义每一个phase具体应该如何操作。这里的phase的作用有点类似于Java语言中的接口,只协商了一个契约,但并没有定义具体的动作。比如说compile这个phase定义了在构建流程中需要经过编译这个阶段,但没有定义应该怎么编译(编译的输入是什么?用什么编译javac/gcc?)。这里具体的动作就是由goal来定义,一个goal在maven中就是一个Mojo(Maven old java object)。Mojo抽象类中定义了一个execute()方法,一个goal的具体动作就是在execute()方法中实现。实现的Mojo类应该放在哪里呢?答案是maven plugin里,所谓的plugin其实也就是一个maven项目,只不过这个项目会引用maven的一些API,plugin项目也具备maven坐标。
      在执行具体的构建时,我们需要为lifecycle的每个phase都绑定一个goal,这样才能够在每个步骤执行一些具体的动作。比如在lifecycle中有个compile phase规定了构建的流程需要经过编译这个步骤,而maven-compile-plugin这个plugin有个compile goal就是用javac来将源文件编译为class文件的,我们需要做的就是将compile这个phase和maven-compile-plugin中的compile这个goal进行绑定,这样就可以实现Java源代码的编译了。有点绕,多看几遍。那么有人就会问,在哪里绑定呢?答案是在pom.xml<build>元素中配置即可。例如:
    <build> 
        <plugins> 
            <plugin> 
                <artifactId>maven-myquery-plugin</artifactId> 
                <version>1.0</version> 
                <executions> 
                    <execution> 
                        <id>execution1</id> 
                        <phase>test</phase> 
                        <configuration> 
                            <url>http://www.foo.com/query</url> 
                            <timeout>10</timeout> 
                            <options> 
                                <option>one</option> 
                                <option>two</option> 
                                <option>three</option> 
                            </options> 
                        </configuration> 
                        <goals> 
                            <goal>query</goal> 
                        </goals> 
                    </execution> 
                </executions> 
            </plugin> 
        </plugins> 
    </build>
    就将maven-myquery-plugin中的query这个goal绑定到了test这个phase,后续在maven执行到test phase时就会执行query goal。还有有人可能会问,我都没有指定Java源文件的位置,编译啥?这就引出了maven的design principle。在maven中,有一个非常著名的principle就是convention over configuration(约定优于配置)。这一点和ant有非常大的区别,例如使用ant来进行编译时,我们需要指定源文件的位置,输出文件的位置,javac的位置,classpath... ...在maven中这些都是不需要,若没有手动配置,maven默认从<项目根目录>/src/main/java这个目录去查找Java源文件,编译后的class文件会保存在<项目根目录>/target/classes目录。在maven中,所有的PO都有一个根对象,就是Super POM。Super POM中定义了所有的默认的配置项。Super POM对应的pom.xml文件可以在maven安装目录下lib/maven-model-builder-3.0.3.jar:org/apache/maven/model/pom-4.0.0.xml中找到。用一张图来表示maven Lifecycle,phase,goal之间的关系:
  • 相关阅读:
    db2新添用户
    merge的用法
    oracle常用命令
    oracle建用户
    获得当前时间的PRO
    全部快捷方式图标变成LNK文件怎么办
    随机生成数据的三种方法
    db2查看表空间
    db2疑难解决
    AVG()和to_date()函数的使用
  • 原文地址:https://www.cnblogs.com/tooy/p/7308800.html
Copyright © 2020-2023  润新知