Maven项目管理工具:Maven继承

樵夫2021-10-08 14:29

    我们知道Maven依赖是具有传递性的,例如A依赖于B,B依赖于C,在不考虑依赖范围等因素的情况下,Maven会根据依赖传递机制,将间接依赖C引入到A中。但如果A出于某种原因,希望将间接依赖C排除,那该怎么办呢?Maven为用户提供了两种解决方式:可选依赖(OptionalDependencies)以及排除依赖(DependencyExclusions)。

    可选依赖

    假设存在这样的依赖关系,A依赖于B,B依赖于X,B又依赖于Y。B实现了两个特性,其中一个特性依赖于X,另一个特性依赖于Y,且两个特性是互斥的关系,用户无法同时使用两个特性,所以A需要排除X,此时就可以在B中将X设置为可选依赖。

    设置可选依赖

    在B的POM关于X的依赖声明中使用optional元素,将其设置成可选依赖,示例配置如下。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>B</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>X</artifactId>
            <version>1.0-SNAPSHOT</version>
            <!--设置可选依赖  -->
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

  关于optional元素及可选依赖说明如下:

    可选依赖用来控制当前依赖是否向下传递成为间接依赖;

    optional默认值为false,表示可以向下传递称为间接依赖;

    若optional元素取值为true,则表示当前依赖不能向下传递成为间接依赖。

    排除依赖

    与上文的应用场景相同,也是A希望排除间接依赖X,除了在B中设置可选依赖外,我们还可以在A中将间接依赖X排除。

    排除依赖是通过在A项目中使用exclusions元素实现,该元素下可以包含若干个exclusion子元素,用于排除若干个间接依赖,示例代码如下。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>A</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>B</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <!-- 设置排除 -->
                <!-- 排除依赖必须基于直接依赖中的间接依赖设置为可以依赖为 false -->
                <!-- 设置当前依赖中是否使用间接依赖 -->
                <exclusion>
                    <!--设置具体排除-->
                    <groupId>net.biancheng.www</groupId>
                    <artifactId>X</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>

    关于exclusions元素及排除依赖说明如下:

    排除依赖是控制当前项目是否使用其直接依赖传递下来的接间依赖;

    exclusions元素下可以包含若干个exclusion子元素,用于排除若干个间接依赖;

    exclusion元素用来设置具体排除的间接依赖,该元素包含两个子元素:groupId和artifactId,用来确定需要排除的间接依赖的坐标信息;

    exclusion元素中只需要设置groupId和artifactId就可以确定需要排除的依赖,无需指定版本version。

    可选依赖VS排除依赖

    可选依赖和排除依赖都能在项目中将间接依赖排除在外,但两者实现机制却完全不一样。

    可选依赖是控制当前项目的依赖是否向下传递;

    排除依赖是控制当前项目是否使用其直接依赖传递下来的接间依赖;

    可选依赖的优先级高于排除依赖;

    若对于同一个间接依赖同时使用可选依赖和排除依赖进行设置,那么可选依赖的取值必须为false,否则排除依赖无法生效。

    我们知道,Maven的依赖传递机制可以一定程度上简化POM的配置,但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同jar包的相同版本,且这些模块之间不存在依赖关系,这就导致同一个依赖需要在多个模块中重复声明,这显然是不可取的,大量的前人经验告诉我们,重复往往意味着更多的劳动和更高的潜在风险。

    在Java面向对象中,我们可以建立一种类的父子结构,然后在父类中声明一些字段和方法供子类继承,这样就可以一定程度上消除重复,做到“一处声明,多处使用”。在Maven的世界中,也有类似的机制,它就是POM继承。

    继承

    Maven在设计时,借鉴了Java面向对象中的继承思想,提出了POM继承思想。当一个项目包含多个模块时,可以在该项目中再创建一个父模块,并在其POM中声明依赖,其他模块的POM可通过继承父模块的POM来获得对相关依赖的声明。对于父模块而言,其目的是为了消除子模块POM中的重复配置,其中不包含有任何实际代码,因此父模块POM的打包类型(packaging)必须是pom。

    如图所示,一个项目中存在如下多个模块。

Maven项目管理工具:Maven继承

    如上图所示:

    App-UI-WAR依赖于App-Core-lib和App-Data-lib。

    Root是App-Core-lib和App-Data-lib的父模块。

    Root在它的依赖部分定义了junit4.9、mysql-connector-java5.1.18以及c3p00.9.1作为其依赖。

    App-UI-WAR的pom.xml配置如下。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>App-UI-WAR</artifactId>
    <version>1.0</version>
    <dependencies>
        <!-- 依赖 App-Core-lib-->
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>App-Core-lib</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- 依赖 App-Data-lib-->
        <dependency>
            <groupId>net.biancheng.www</groupId>
            <artifactId>App-Data-lib</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>
</project>

    父模块POM配置

    父模块Root的pom.xml配置如下。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>Root</artifactId>
    <version>1.0</version>
    <!--定义的父类 POM 打包类型使pom  -->
    <packaging>pom</packaging>
   
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.18</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1</version>
        </dependency>
    </dependencies>
</project>

    在父模块Root的pom.xml中,其打包类型(packaging)为pom,并声明了3个依赖:junit4.9、mysql-connector-java5.1.18以及c3p00.9.1。

    子模块POM配置

    App-Core-lib的pom.xml配置如下。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>App-Core-lib</artifactId>
    <version>1.0</version>
    <parent>
        <groupId>net.biancheng.www</groupId>
        <artifactId>Root</artifactId>
        <version>1.0</version>
        <relativePath>../Root</relativePath>
    </parent>
    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
</project>

    App-Data-lib的pom.xml配置如下。

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.biancheng.www</groupId>
    <artifactId>App-Data-lib</artifactId>
    <version>1.0</version>
    <parent>
        <groupId>net.biancheng.www</groupId>
        <artifactId>Root</artifactId>
        <version>1.0</version>
        <!-- <relativePath>../Root</relativePath> -->
    </parent>
</project>

    在子模块App-Core-lib和App-Data-lib的pom.xml中,使用parent元素声明父模块,其子元素如下表:    

元素 描述 是否必需
groupId 父模块的项目组 id。
artifactId 父模块 id。
version 父模块版本。
relativePath 父模块 POM 的相对路径,默认值为 ../pom.xml。
项目构建时,Maven 会先根据 relativePath 查找父模块 POM,如果找不到,再从本地仓库或远程仓库中查找。

    子模块的POM中,当前模块的groupId和version元素可以省略,但这并不意味着当前模块没有groupId和version,子模块会隐式的从父模块中继承这两个元素,即由父模块控制子模块的公司组织id以及版本,这样可以简化POM的配置。

    查看继承依赖项

    在App-Core-lib和App-Data-lib两个子模块的pom.xml中,只有App-Core-lib声明了一个依赖:log4j1.2.17。那么如何验证子模块是否继承了父模块POM中声明的依赖项呢?

    下面我们需要用到一个插件:maven-dependency-plugin,它可以帮助我们分析项目依赖,其插件目标dependency:list能够列出项目最终解析到的依赖列表,dependency:tree能够进一步的描绘项目依赖树。

    1.打开命令行窗口,跳转到子模块App-Core-lib的目录下,执行以下命令,查看该模块依赖列表。

mvn dependency:list

    命令执行结果如下。

[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< net.biancheng.www:App-Core-lib >-------------------
[INFO] Building App-Core-lib 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ App-Core-lib ---
[INFO]
[INFO] The following files have been resolved:
[INFO]    junit:junit:jar:4.9:compile
[INFO]    log4j:log4j:jar:1.2.17:compile
[INFO]    c3p0:c3p0:jar:0.9.1:compile
[INFO]    mysql:mysql-connector-java:jar:5.1.18:runtime
[INFO]    org.hamcrest:hamcrest-core:jar:1.1:compile
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.921 s
[INFO] Finished at: 2021-04-14T15:09:18+08:00
[INFO] ------------------------------------------------------------------------

    可以看到,App-Core-lib有5个依赖项,其中junit4.9、mysql-connector-java5.1.18以及c3p00.9.1是从父模块Root中继承的;log4j1.2.17是该模块本身的POM中声明的;hamcrest1.1是junit4.9传递下来的依赖项。

    2.在命令行窗口中,跳转到子模块App-Data-lib的目录下,执行以下命令,查看该模块依赖列表。

mvn dependency:list

    命令执行结果如下。

[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< net.biancheng.www:App-Data-lib >-------------------
[INFO] Building App-Data-lib 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ App-Data-lib ---
[INFO]
[INFO] The following files have been resolved:
[INFO]    junit:junit:jar:4.9:compile
[INFO]    c3p0:c3p0:jar:0.9.1:compile
[INFO]    mysql:mysql-connector-java:jar:5.1.18:runtime
[INFO]    org.hamcrest:hamcrest-core:jar:1.1:compile
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.938 s
[INFO] Finished at: 2021-04-14T15:37:28+08:00
[INFO] ------------------------------------------------------------------------

    可以看到,App-Data-lib有4个依赖项,其中junit4.9、mysql-connector-java5.1.18以及c3p00.9.1是从父模块Root中继承的;hamcrest1.1是junit4.9传递下来的依赖项。

    可继承的POM元素

    在上面的例子中,我们可以看出groupId、artifactId以及项目的依赖配置dependencies是可以被继承的,除了这3个元素之外,还有哪些元素可以被继承呢?

    Maven可通过继承获得POM元素,如下表。

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

    以上就是小编为大家整理发布的“Maven项目管理工具:Maven继承”一文,更多相关内容尽在开课吧广场Java教程频道。

Maven项目管理工具:Maven继承

免责声明:本站所提供的内容均来源于网友提供或网络搜集,由本站编辑整理,仅供个人研究、交流学习使用。如涉及版权问题,请联系本站管理员予以更改或删除。
有用
分享
全部评论快来秀出你的观点
登录 后可发表观点…
发表
暂无评论,快来抢沙发!
高并发编程训练营