zoukankan      html  css  js  c++  java
  • 06 Maven 聚合和继承

    Maven 聚合和继承

    1. 聚合

    2. 继承

    <parent>
        <groupId>org.apache.karaf.demos</groupId>
        <artifactId>demos</artifactId>
        <version>4.1.5</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    

    正确设置 relativepath 非常重要。考虑这样一个情况,开发团队的新成员从源码库签出一个包含父子模块关系的 Maven 项目。由于只关心其中的某一个子模块,它就直接到该模块的目录下执行构建,这个时候,父模块是没有被安装到本地仓库的,因此如果子模块没有设置正确的的 relativepath, Maven 将无法找到父 POM,这将直接导致构建失败。如果 Maven 能够根据 relativepath 找到父 POM,它就不需要再去检査本地仓库。

    2.1 可继承的 POM 元素

    groupId 和 version 是可以被继承的,那么还有哪些 POM 元素可以被继承呢?以下是一个完整的列表,并附带了简单的说明:

    1. groupId 项目组ID,项目坐标的核心元素
    2. version 项目版本,项目坐标的核心元素
    3. description 项目的描述信息
    4. organization 项目的组织信息。
    5. inceptionYear 项目的创始年份。
    6. url 项目的URL地址。
    7. developers 项目的开发者信息。
    8. contributors 项目的贡献者信息。
    9. distributionManagement 项目的部署配置。
    10. issueManagement 项目的缺陷跟踪系统信息
    11. ciManagement 项目的持续集成系统信息。
    12. scm 项目的版本控制系统信息。
    13. mailinglists 项目的邮件列表信息
    14. properties 自定义的 Maven 属性。
    15. dependencies 项目的依赖配置。
    16. dependencyManagement 项目的依赖管理配置。
    17. repositories 项目的仓库配置。
    18. build 包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等。
    19. reporting 包括项目的报告输出目录配置、报告插件配置等。

    2.2 依赖管理

    <dependencyManagement>
    </dependencyManagement>
    

    2.3 插件管理

    <build>
        <pluginManagement>
        </pluginManagement>
    </build>
    

    2.4 聚合与继承的关系

    对于聚合模块来说,它知道有哪些被聚合的模块,但那些被聚合的模块不知道这个聚合模块的存在。

    对于继承关系的父 POM 来说,它不知道有哪些子模块继承于它,但那些子模块都必须知道自己的父 POM 是什么。

    如果非要说这两个特性的共同点,那么可以看到,聚合 POM 与继承关系中的父 POM 的 packaging 都必须是 pmn,同时,聚合模块与继承关系中的父模块除了 POM 之外都没有实际的内容,如图1 所示

    图6.1 聚合关系与继承关系的比较

    图1 聚合关系与继承关系的比较

    3. 约定优于配置

    Maven 提倡“约定优于配置”(Convention Over Configuration),这是 Maven 最核心的设计理念之一。

    那么为什么要使用约定而不是自己更灵活的配置呢?原因之一是,使用约定可以大量减少配置。Maven 只需要一个最简单的 POM 就可以搞定。

    <project>
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.apache.karaf.demos</groupId>
        <artifactId>org.apache.karaf.demos.branding.shell</artifactId>
        <version>4.1.5</version>
    </project>
    

    这段配置简单得令人惊奇,但为了获得这样简洁的配置,用户是需要付出一定的代价的,那就是遵循 Maven 的的约定。Maven 会假设用户的项目是这样的:

    1. 源码目录为 src/main/java/
    2. 编译输出日录为 targel/classes
    3. 打包方式为 jar 包
    4. 输出目录为 target/

    遵循约定虽然损失了一定的灵活性,用户不能随意安排目录结构,但是却能减少配置。更重要的是,遵循约定能够帮助用户遵守构建标准。

    也许这时候有读者会问,如果我不想遵守约定该怎么办?这时,请首先问自己三遍,你真的需要这么做吗?如果仅仅是因为喜好,就不要要个性,个性往往意味着辆牲通用性,意味着增加无谓的复杂度:例如, Maven 允许你自定义源码目录:

    <project>
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.apache.karaf.demos</groupId>
        <artifactId>org.apache.karaf.demos.branding.shell</artifactId>
        <version>4.1.5</version>
        <build>
            <sourceDirectory>src/java</sourceDirectory>
        </build>
    </project>
    

    该例中源码目录就成了 src/java 而不是默认的 src/main/java。但这往往会造成交流问题,习惯 Maven 的人会奇怪,源代码去哪里了?当这种自定义大量存在的时候,交流成本就会大大提高。只有在一些特殊的情况下,这种自定义配置的方式才应该被正确使用以解决实际问题。例如你在处理遗留代码,并且没有办法更改原来的目录结构,这个时候就只能让 Maven 妥协。

    本书曾多次提到超级 POM,任何一个 Maven 项目都隐式地继承自该 POM,这有点类似于任何一个 Java 类都隐式地继承于 Object 类。서此,大量超级 POM 的配置都会被所有 Maven 项目继承,这些配置也就成为了 Maven 所提倡的约定。对于 Maven3 超级 POM 在在文件 $MAVEN_HOME/lib/maven-model-builder-3.5.0.jar 中的 org/apache/maven/model/pom-4.0.0.xml 路径下。

    <repositories>
        <repository>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    
    <pluginRepositories>
        <pluginRepository>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <updatePolicy>never</updatePolicy>
            </releases>
        </pluginRepository>
    </pluginRepositories>
    

    首先超级 POM 定义了仓库及插件仓库,两者的地址都为中央仓库 htp://repo. mavel.org/ maven2,并且都关闭了 SNAPSHOT 的支持。这也就解释了为什么 Maven 默认就可以按需要从中央仓库下载构件。

    <build>
        <directory>${project.basedir}/target</directory>
        <outputDirectory>${project.build.directory}/classes</outputDirectory>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
        <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
        <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
        <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
        <resources>
            <resource>
                <directory>${project.basedir}/src/main/resources</directory>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>${project.basedir}/src/test/resources</directory>
            </testResource>
        </testResources>
    </build>
    

    这里依次定义了项目的主输出目录、主代码输出目录、最终构件的名称格式、测试代码输出目录、主源码目录、脚本源码目录、测试源码目录、主资源目录和测试资源目录。这就是 Maven 项目结构的约定。紧接着超级 POM 为核心插件设定版本。

    <pluginManagement>
        <!-- NOTE: These plugins will be removed from future versions of the super POM -->
        <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->
        <plugins>
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.3</version>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2-beta-5</version>
            </plugin>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.8</version>
            </plugin>
            <plugin>
                <artifactId>maven-release-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </pluginManagement>
    

    可以看到,超级 POM 实际上很简单,但从这个 POM 我们就能够知晓 Maven 约定的由来,不仅理解了什么是约定,为什么要遵循约定,还能明白约定是如何实现的。

    4. 反应堆

    在一个多模块的 Maven 项目中,反应堆(Reactor)是指所有模块组成的一个构建结构。对于单模块的项目,反应堆就是该模块本身,但对于多模块项目来说,反应堆就包含了各模块之间继承与依赖的关系,从而能够自动计算出模块构建顺序。

    4.1 反应雄的构建序

    实际的构建顺序是这样形成的: Maven 按序读取 POM,如果该 POM 没有依赖模块,那么就构建该模块,否则就先构建其依赖模块,如果该依赖还依赖于其他模块,则进一步先构建依赖的依赖。

    4.2 裁剪反应雄

    一般来说,用户会选择构建整个项目或者选择构建单个模块,但有些时候,用户会想要仅仅构建完整反应堆中的某些个模块。换句话说,用户需要实时地裁剪反应堆。

    Maven 提供很多的命令行选项支持裁剪反应堆,输入 mvn -h 可以看到这些选项:

    1. -am --also-make 同时构建所列模块的依赖模块口

    2. -amd --also-make-dependents 同时构建依赖于所列模块的模块

    3. -pl --projects 构建指定的模块,模块间用逗号分隔口

    4. -rf --resume-from 从指定的模块回复反应堆

      使用-pl选项指定构建某几个模块

      mvn clean install -pl account-email account-persist

      使用 -amd 选项可以同时构建依赖于所列模块的模块

      mvn clean install -pl account-parent -amd

      使用-rf选项可以在完整的反应堆构建顺序基础上指定从哪个模块开始构建

      mvn clean install - rf account-email

  • 相关阅读:
    js中的原生Ajax和JQuery中的Ajax
    this的用法
    static的特性
    时政20180807
    java compiler没有1.8怎么办
    Description Resource Path Location Type Java compiler level does not match the version of the installed Java project facet Unknown Faceted Project Problem (Java Version Mismatch)
    分词器
    [数算]有一个工程甲、乙、丙单独做,分别要48天、72天、96天完成
    一点感想
    解析Excel文件 Apache POI框架使用
  • 原文地址:https://www.cnblogs.com/binarylei/p/8647312.html
Copyright © 2011-2022 走看看