第七节:Maven中的聚合与继承

来源:互联网 发布:网页游戏如何修改数据 编辑:程序博客网 时间:2024/06/06 01:37
     Maven的聚合特性能够把项目的各个模块聚合在一起构建,而Maven的继承特性则能帮助抽取各模块间相同的依赖和插件配置,还能促进各个模块之间配置的一致性。

聚合:
     我们在开发过程中,将项目拆分成独立的子模块,每个模块都是一个独立的maven project,在开始的时候我们可以独立的编译和测试运行每个模块,但是我们期望能够使用简单的操作来完成所有项目的编译等工作,这时Maven给出了聚合的配置方式。我们可以建立一个专门负责聚合工作的Maven project — aggregator,然后通过该模块构建整个项目的所有模块。
     该聚合项目特征以及约定:
  • 该aggregator本身也做为一个Maven项目,它必须有自己的POM
  • 约定:为了方便构建,通常将聚合模块放在项目目录层的最顶层,其它子模块作为其子目录存在。这样当我们打开项目的时候,第一个看到的就是聚合模块的POM。
  • 聚合模块的版本和被聚合模块版本需一致
  • 它的打包方式必须为:pom,即<packaging>pom</packaging>
  • 引入了新的元素:<modules>及其下的<module>,用户可以在一个打包方式为POM的Maven项目下声明任意数量的module元素来实现模块的聚合。我们声明<module>child-project-A</module>,那么聚合项目的POM就会默认去./child-project-A的目录下去寻找子模块,所以在module中声明的子模块应与聚合项目的POM处于同一目录下。如果我们不遵循约定,将子模块放于跟聚合模块同一个目录下,则modules的声明需要改成<module>../child-project-A</module>.
  • 聚合模块的内容仅仅是一个pom.xml文件,因为它只是用来帮助其它模块构建的工具,本身并没有实质的内容,所以它不包含src/main/java、src/test/java等目录.
     

继承:
     我们在项目开发的过程中,可能多个模块独立开发,但是多个模块可能依赖相同的元素或者需要引入相同的插件,比如说每个模块都需要Junit,使用spring的时候,其核心jar也必须都被引入,在编译的时候,maven-compiler-plugin插件也要被引入,这在每一个子模块里都是需要配置的,但是通过POM继承,我们可以抽取出重复的配置,精简代码。

     我们可以建立一个专门负责继承工作的父模块 — parent,他有以下特征:
  • 该parent本身也做为一个Maven项目,它必须有自己的POM
  • 由于它只是为了消除配置的重复,所以继承模块的内容仅仅是一个pom.xml文件,本身并没有实质的内容
  • 它的打包方式必须为:pom,即<packaging>pom</packaging>

     继承他的子模块有以下特征:
  • 在继承他的子模块的pom文件中,我们用<parent>元素来声明父模块,<parent>元素下的子元素groupId,artifactId,version指定了父模块的坐标,<relativePath>元素指定了父模块pom文件的路径(相对于该子模块的pom),
          其默认值为../,相当于去上一层目录找父pom。但是有时候会有问题,例如我们只从仓库中迁出了一个子模块,此时
          <relativePath>元素多半就失效了,子模块只能根据父模块的坐标再去仓库中寻找。
  • 子模块必须显示声明artifactId,他隐式得从父模块继承了groupId和version两个元素,只要当子模块与父模块的这两个元素不一致时,才需要显式声明他们。


可继承的POM元素:
  • groupId:项目组ID,项目坐标的核心元素
  • version:项目版本, 项目坐标的核心元素
  • dependencies:项目的依赖配置
  • repositories:项目的仓库配置
  • distributionManagement:项目的部署配置
  • dependencyManagement:项目的依赖管理配置
  • pluginManagement:项目的插件管理配置
  • build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
  • properties:自定义的maven属性
  • description: 项目的描述信息
  • organization: 项目的组织信息
  • inceptionYear: 项目的创始年份
  • url: 项目的URL地址
  • developers: 项目开发者信息
  • contributors: 项目的贡献者信息
  • issueManagement: 项目的缺陷跟踪系统信息
  • ciManagement: 项目的持续集成系统信息
  • scm: 项目的版本控制系统信息
  • mailingLists: 项目的邮件列表信息
  • reporting: 包括项目的报告输出目录配置、报告插件配置等

依赖管理:
     由上我们可知dependencies是可以被继承的,我们就想到把几个子模块共同依赖的元素A转移到parent中,这样我们又进一步的优化了配置。可是问题也随之而来,如果有一天又创建了一个继承parent的子模块,但是这个模块不需要依赖元素A,n那这时候如何处理?
     在父模块的POM中dependencyManagement元素帮我们解决了这个问题。我们在dependencyManagement元素配置
依赖(同样是使用dependencies,dependency元素),但是这里(父模块的POM中)声明的依赖不会给父模块引入依赖也不会给子模块引入依赖,这段配置会被继承,子模块只有在POM中显式得声明依赖的groupId与artifactId,才能得到我们从父模块中继承而来的完整的依赖配置(例如包含了版本号,依赖范围等),如果不声明,即使依赖已经在父模块的dependencyManagement中被声明了,但是也不会有什么实际的效果。       

     通过这样的配置,我们可以统一项目范围中依赖的版本,降低各个子模块间由于依赖版本不一样可能引起的冲突。
     更进一步,如果我们有多个父模块,那又该怎么抽取出各个父模块POM文件中重复的配置呢?我们只要在各个父模块POM文件中引入这些配置就好了。这里使用了一个新的依赖范围:import,并且设置这个依赖的type为pom,代码如下:


插件管理:
     类似于管理依赖的dependencyManagement,Maven提供了pluginManagement来管理插件,他的机制和dependencyManagement一样,当子模块需要不同的插件配置,可以自行配置以覆盖父模块的pluginManagement配置。
<project>    ...    <build>        <pluginManagement>            <plugins>                <plugin>                    <artifactId>maven-assembly-plugin</artifactId>                    <version>2.2-beta-2</version>                    <executions>                        <execution>                            <id>create-project-bundle</id>                            <phase>package</phase>                            <goals>                                <goal>single</goal>                            </goals>                            <configuration>                                <descriptorRefs>                                    <descriptorRef>project</descriptorRef>                                </descriptorRefs>                            </configuration>                        </execution>                    </executions>                </plugin>            </plugins>        </pluginManagement></build> ...</project>
 
<build>    <plugins>        <plugin>            <artifactId>maven-assembly-plugin</artifactId>        </plugin>    </plugins></build>

继承和聚合总结:
     对于聚合模块来说,它知道有哪些被聚合的模块,而对于被聚合的模块来说,它们不知道被谁聚合了,也不知道它的存在
     对于继承关系的父POM来说,它不知道自己被哪些子模块继承了,对于子POM来说,它必须知道自己的父POM是谁
     在一些实践中我们会发现:一个POM既是聚合POM,又是父POM,这么做主要是为了方便。

约定优于配置:
     这是Maven最核心的设计理念之一,他大大简化了我们需要手动配置的内容,我们举个例子:Maven中约定了源码目录为src/main/java/,编译输出目录为target/classes/,有了这个约定,我们就不再需要手动创建这些目录,Maven会自动创建他们,在执行像mvn clean install这样的命令时,只要按照约定,我们不需要额外配置什么,这条命令就可以用来构建几乎任何的Maven项目。

反应堆:
     反应堆是指所有模块组成的一个构建结构,包含了各个模块之间的依赖和继承关系,能够计算出合理的模块构建顺序。
     构建顺序:按照聚合项目中<modules>中声明<module>元素的顺序来读取各个子模块的POM文件,如果POM文件没有依赖模块(父模块),那么就构建该模块,否则就先构建其依赖模块,如果该依赖还依赖于其他模块,则进一步先构建依赖的依赖模块。
     当我们想仅仅构建完整反应堆中的某些模块时,我们需要调用以下命令:
  • -am(also-make):同时还会构建所列项目的依赖模块(父模块)
  • -amd(also-make-dependents):同时还会构建所列模块的子模块
  • -pl(-project)<arg..> : 构建指定模块,模块间用逗号分隔
  • -rf(resume-from)<arg> :在完整的反应堆构建顺序基础上指定从哪个模块开始构建
    假设有child-A,child-B依赖于parent,完整的反应堆构建顺序为:parent ---> child-A —> child-B
     mvn clean install -pl child-A -am:此时会先构建parent,在构建child-A
     mvn clean install -pl child-A,child-B:此时会构建child-A和child-B,但是不会构建parent
     mvn clean install -pl parent -amd:此时会先构建parent,然后再构建child-A和child-B
     mvn clean install -pl child-A -amd:此时会从完整的反应堆构建顺序的child-A开始到child-B

     
0 0
原创粉丝点击