zoukankan      html  css  js  c++  java
  • Maven 项目之间的关系

    一、继承

    1、继承关系介绍

    一个 Maven 项目 B 继承另外一个 Maven 项目 A ,那么 A 称为父项目, B 就称为子项目,所谓的项目之间的关系其实就是 pom 与 pom 之间的关系,(因为一个项目有且只有一个 pom.xml ,而 pom.xml 就是描述对应项目的)

    使用场景:如果多个子项目中使用的是相同的依赖或插件,此时我们可以把相同的配置抽取到一个父项目中,进行统一的管理,保持一致性.

    这里的管理具体是指:

    • 子项目继承父项目的依赖,实现统一管理子项目有哪些依赖.
    • 父项目管理依赖的版本,实现统一管理子项目依赖的版本.

    值得一提的是,这里和全局变量 properties 有些不同, properties 常用来统一管理同一个项目中一类依赖的版本(例如统一管理 Spring 系列的 jar 包版本),而 Maven 继承常用来统一管理多个项目的同一个 jar 包版本

    父子工程的项目,子项目最好是放在父项目的目录下,不要放在其它目录下,父项目不做任何逻辑处理,仅仅是为了管理所有的子项目,父项目里面只保留 pom.xml 就可以了.

    2、IDEA 创建 Maven 项目

    IDEA 创建 3 个 module ,名称分别为 parent、child01、child02

    2.1、file---->new---->module

    2.2、选择 Maven---->选择合适版本的 SDK---->选择合适的模板

    我这里是利用 maven-archetype-quickstart 骨架创建一个 Java 项目

    2.3、指定好相应配置

    2.4、为了防止创建项目过慢,添加 archetypeCatalog=internal

    2.5、child01、child02 创建方式和上面步骤相同,创建好的项目结构如下:

    3、配置继承关系

    我们这里配置成 child01、child02 都继承 parent 这个项目

    这里说一下项目的打包方式, packaging 标签的取值有 jar (默认)、war、pom

    打包方式:
    jar: java 项目的打包方式,默认值.
    war: web 项目的打包方式.
    pom: 父项目的专有打包方式,该种方式,本项目不会被打包成 jar 或 war ,项目里 src 目录下代码无效(可删除), pom.xml 有效,只是作为其它项目的父项目使用.

    3.1、设置父项目 pom.xml 配置打包方式为 pom

    <groupId>com.xiaomaomao.archetype</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    3.2、child01

    <groupId>com.xiaomaomao.mavenAnalyse</groupId>
    <artifactId>child01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--子项目将来打包成 jar 包-->
    <packaging>jar</packaging>
    <name>child01</name>
    
    <!--使用 parent 标签表示该项目继承父项目,使用父项目具体坐标来引用父项目 -->
    <parent>
    	<!--父项目的坐标-->
    	<groupId>com.xiaomaomao.mavenAnalyse</groupId>
    	<artifactId>parent</artifactId>
    	<version>1.0-SNAPSHOT</version>
    	<!--指定父项目的 pom.xml 文件的相对物理路径, ../是上一级目录,
    	../parent/pom.xml:相对于当前pom.xml ,先到上一级,再到 parent 目录,
    	找到parent目录下的 pom.xml ,鼠标左键点击如果能跳到 parent 项目的 pom.xml
    	 那么就配置对了 -->
    	<relativePath>../parent/pom.xml</relativePath>
    </parent>

    3.3、child02

    <groupId>com.xiaomaomao.mavenAnalyse</groupId>
    <artifactId>child02</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>child02</name>
    
    <parent>
    	<groupId>com.xiaomaomao.mavenAnalyse</groupId>
    	<artifactId>parent</artifactId>
    	<version>1.0-SNAPSHOT</version>
    	<relativePath>../parent/pom.xml</relativePath>
    </parent>
    

    3.4、在 parent 的 pom.xml 中添加一些测试的依赖,child01、child02 pom.xml 中不配置任何依赖

    <dependencies>
    	<!--配置spring-->
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-context</artifactId>
    		<version>${spring-version}</version>
    	</dependency>
    	<!--配置webmvc-->
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-webmvc</artifactId>
    		<version>${spring-version}</version>
    	</dependency>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.17</version>
    	</dependency>
    	<dependency>
    		<groupId>junit</groupId>
    		<artifactId>junit</artifactId>
    		<version>4.11</version>
    		<scope>test</scope>
    	</dependency>
    </dependencies>
    

    3.5、依赖继承关系图

    从图中可以很明显的看出, child01、child02 继承了 parent 中的依赖

    4、父项目对子项目依赖的版本控制

    举例: child01 模块使用 log4j 做日志记录,而 child02 模块使用 commons-logging 做日志记录(实际工作中并不会出现此种情况)

    那么我们可以这样做

    父工程中不引入 log4j 的依赖,也不引入 commons-logging 的依赖, child01 中声明使用 log4j 

    <dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.17</version>
    </dependency>
    

    child02 中声明使用 commons-logging

    <dependency>
    	<groupId>commons-logging</groupId>
    	<artifactId>commons-logging</artifactId>
    	<version>1.0</version>
    </dependency>
    

    这样我们就实现了在不同的子工程中引用自己所需要的依赖了,这样看上去很美好,但是呢这里会遗留下一个问题,如果有一天我们需要对各个子模块的依赖进行版本切换,我们只能找到对应的子模块,然后到各个子模块中去切换依赖的版本,这样很不方便,这个时候怎么办呢?

    你可能想到了我们不是有父模块吗?让父模块对子模块的依赖进行统一管理就可以了,不错,我们是可以使用父模块,但是还是会有问题,为什么呢?

    如果父模块中同时引入 log4j 和 commons-logging 的依赖,确实可以统一对子模块中的依赖进行管理

    <dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.17</version>
    </dependency>
    <dependency>
    	<groupId>commons-logging</groupId>
    	<artifactId>commons-logging</artifactId>
    	<version>1.0</version>
    </dependency>
    

    但是呢,这样做还是会存在一个问题, child01、child02 都会继承父模块中的依赖,这样原本只需要 log4j 的 child01 就会继承到自己不需要的 commons-logging,同理,child02 也会继承到 log4j ,这样的话

    子模块中就很容易产生 jar 包的冲突,并且子模块会继承一些自己压根就不需要的 jar 包,那么怎么办呢?

    这里我们可以使用 <dependencyManagement> 标签来解决我们上述的问题,这个标签的作用其实相当于一个对所依赖 jar 包进行版本管理的管理器.( dependencyManagement 里只是声明依赖,并不实现引入)

    parent 中 pom.xml

    <groupId>com.xiaomaomao.mavenAnalyse</groupId>
    <artifactId>parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--父项目的特有的打包方式,必须声明为 pom-->
    <packaging>pom</packaging>
    <name>parent</name>
    
    <properties>
    	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    	<maven.compiler.source>1.7</maven.compiler.source>
    	<maven.compiler.target>1.7</maven.compiler.target>
    	<!--统一管理 Spring 系列的依赖的版本-->
    	<spring-version>5.2.8.RELEASE</spring-version>
    </properties>
    
    <!--dependencies 中的依赖会被子项目继承-->
    <dependencies>
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-context</artifactId>
    		<version>${spring-version}</version>
    	</dependency>
    	<dependency>
    		<groupId>org.springframework</groupId>
    		<artifactId>spring-webmvc</artifactId>
    		<version>${spring-version}</version>
    	</dependency>
    </dependencies>
    
    <!--dependencyManagement 标签中声明的依赖,只是作为一个 jar 包统一管理的管理器
    实际上该标签中声明的依赖不会被引入-->
    <dependencyManagement>
    	<dependencies>
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>1.2.17</version>
    		</dependency>
    		<dependency>
    			<groupId>commons-logging</groupId>
    			<artifactId>commons-logging</artifactId>
    			<version>1.0</version>
    		</dependency>
    	</dependencies>
    </dependencyManagement>
    

    child 01 中 pom.xml

    <groupId>com.xiaomaomao.mavenAnalyse</groupId>
    <artifactId>child01</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--子项目将来打包成 jar 包,默认值就是 jar-->
    <packaging>jar</packaging>
    <name>child01</name>
    
    <!--使用 parent 标签表示该项目继承父项目,使用具体坐标定位父项目-->
    <parent>
    	<!--父项目的坐标-->
    	<groupId>com.xiaomaomao.mavenAnalyse</groupId>
    	<artifactId>parent</artifactId>
    	<version>1.0-SNAPSHOT</version>
    	<!--指定父项目的 pom.xml 文件的相对物理路径, ../是上一级目录,
    	../parent/pom.xml:相对于当前pom.xml ,先到上一级,再到 parent 目录,
    	找到parent目录下的 pom.xml ,鼠标左键点击如果能跳到 parent 项目的 pom.xml
    	 那么就配置对了 -->
    	<relativePath>../parent/pom.xml</relativePath>
    </parent>
    
    <dependencies>
    	<!--依赖的版本已经由父项目通过 dependencyManagement 进行统一管理了
    	如果没有注明版本:那么就会默认使用父项目中的版本
    	如果显示的声明了版本,就使用自己声明的版本-->
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    	</dependency>
    </dependencies>
    

    child02 中 pom.xml

    <groupId>com.xiaomaomao.mavenAnalyse</groupId>
    <artifactId>child02</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>child02</name>
    
    <parent>
    	<groupId>com.xiaomaomao.mavenAnalyse</groupId>
    	<artifactId>parent</artifactId>
    	<version>1.0-SNAPSHOT</version>
    	<relativePath>../parent/pom.xml</relativePath>
    </parent>
    
    <dependencies>
    	<dependency>
    		<groupId>commons-logging</groupId>
    		<artifactId>commons-logging</artifactId>
    		<!--子项目中显示的声明依赖版本,那么就使用子项目中声明的版本-->
    		<version>1.2</version>
    	</dependency>
    </dependencies>
    

    如上配置之后效果如下:

    通过 dependencyManagement 标签,我们实现了最终的目的

    子工程中相同的模块抽取到父工程的 dependencies 标签中,让每个子工程可以继承

    子工程中不同的部分声明在父工程的 dependencyManagement 中,该标签中的依赖不会被父工程引用,但是使用了该标签可以对子模块中不同的依赖进行版本管理,例如:父工程中切换 log4j 和 commons-logging 的版本之后,如果子工程没有显示的声明版本,那么会随着父工程中版本的切换而同步切换

    这里面还有一个 pluginManagement 标签,它是父工程对子工程插件版本的统一管理,和 dependencyManagement 的使用相同

     

    二、聚合

    聚合:将多个子项目添加到一个父项目中,然后通过对父项目进行操作( Maven 命令),从而实现对所有聚合的子项目的操作

    例如:父项目执行 mvn package 操作,子项目也会被打包.

    继承和聚合的区别

    继承是告诉子项目它的父项目是谁,在哪里,聚合是告诉父项目它的子项目有哪些,分别在哪里

    那么怎么实现聚合呢?

    在父项目的 pom.xml 中配置

    <!--子项目中定位父项目使用的是 pom.xml 来定位的
    而父项目定位子项目使用的名字来定位的,为什么不使用
    pom.xml 来定位呢?个人猜测可能是同一路径下有多个子
    项目,使用 pom.xml 不能准确的定位到是哪个子项目-->
    <modules>
    	<module>../child01</module>
    	<module>../child02</module>
    </modules>
    

    测试聚合后的效果

      

    三、依赖关系

    1、依赖关系的传递

    项目A---->项目B---->项目C 

    概念:如果项目 A 依赖于项目 B ,项目 B 依赖于项目 C ,则项目 A 也依赖于项目 C ,这就叫做依赖的传递

    如果觉得依赖这个词不是很好理解,可以把依赖翻译为使用,即项目 A 使用项目 B ,项目 B 使用项目 C

    下面我们就来演示一个案例: child01 依赖 child02 , child02 依赖 child03 ,child03 依赖 log4j

    // child01 的 pom.xml
    <!--child01 依赖 child02-->
    <dependencies>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child02</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    </dependencies>
    
    // child02 的 pom.xml
    <!--child02 依赖 child03-->
    <dependencies>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child03</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    </dependencies>
    
    // child03 的 pom.xml
    <!--child03 依赖 log4j 1.2.12-->
    <dependencies>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.12</version>
    	</dependency>
    </dependencies>
    

    查看依赖关系

    从上图中可以看到,实现了依赖传递

    2、控制依赖的传递

    并不是所有的依赖都会传递

    scope 为 compile 的依赖会发生传递

    下面这些情况的依赖是不会传递的

    • scope 为 test 的依赖不具有依赖传递性,但是具有继承性
    • scope 为 provided 的依赖不具有依赖的传递性,但是具有继承性
    • 配置 optional 标签为 true 的依赖不具有依赖传递性

    修改 child03 pom.xml 中的相关依赖

    <dependencies>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.12</version>
    	</dependency>
    	<dependency>
    		<groupId>com.fasterxml.jackson.core</groupId>
    		<artifactId>jackson-databind</artifactId>
    		<version>2.11.2</version>
    	</dependency>
    	<dependency>
    		<groupId>junit</groupId>
    		<artifactId>junit</artifactId>
    		<version>4.11</version>
    		<scope>test</scope>
    	</dependency>
    	<dependency>
    		<groupId>javax.servlet</groupId>
    		<artifactId>servlet-api</artifactId>
    		<version>2.5</version>
    		<scope>provided</scope>
    	</dependency>
    	<dependency>
    		<groupId>org.mybatis</groupId>
    		<artifactId>mybatis-spring</artifactId>
    		<version>2.0.5</version>
    		<!--optional 的默认值为 false-->
    		<optional>true</optional>
    	</dependency>
    </dependencies>
    

    查看依赖的传递性

    3、依赖传递的原则

    使用 Maven 不会出现 jar 包冲突,因为其通过两个原则来保证

    3.1、就近原则,依赖的 jar 包距离本项目的层级越近(路径越短),优先级越高.

    依赖配置

    // child01 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child02</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    </dependencies>
    
    // child02 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child03</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.12</version>
    	</dependency>
    </dependencies>
    
    // child03 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.17</version>
    	</dependency>
    </dependencies>
    

    查看结果

    2、优先声明原则,在同一个 pom.xml 的 dependecy 标签里面, jar 包写在上面,优先级就越高.

    依赖配置

    // child01 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child02</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    </dependencies>
    
    // child02 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child03</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    	<dependency>
    		<groupId>com.xiaomaomao</groupId>
    		<artifactId>child04</artifactId>
    		<version>1.0-SNAPSHOT</version>
    	</dependency>
    </dependencies>
    
    // child03 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.17</version>
    	</dependency>
    </dependencies>
    
    // child04 中的 pom.xml
    <dependencies>
    	<dependency>
    		<groupId>log4j</groupId>
    		<artifactId>log4j</artifactId>
    		<version>1.2.12</version>
    	</dependency>
    </dependencies>

    查看结果

    3、这两个原则的优先级关系?

    首先按照就近原则,如果传递的依赖距离本项目的层级相同,那么再按照优先声明原则传递依赖

    4、不要传递的依赖

    在实际情况中有些依赖我们不希望传递,那么这些依赖该怎么处理呢?

    4.1、如果当前的 pom 我们可以修改,使用 optional 标签即可

    <dependency>
    	<groupId>org.mybatis</groupId>
    	<artifactId>mybatis-spring</artifactId>
    	<version>2.0.5</version>
    	<!--optional 的默认值为 false-->
    	<optional>true</optional>
    </dependency>

    4.2、如果当前的 pom.xml 我们不能修改,使用 exclusion 标签

    <dependencies>
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.11.2</version>
          <exclusions>
    	    <!--使用 exclusion 标签排除不需要的依赖-->
            <exclusion>
              <groupId>com.fasterxml.jackson.core</groupId>
              <artifactId>jackson-annotations</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
    </dependencies>

     

     

     

     

     

  • 相关阅读:
    深入浅出Win32多线程程序设计【2】线程控制
    深入浅出Win32多线程程序设计【1】基本概念
    在两个ASP.NET页面之间传递值
    Javascript基础
    DataGrid的几个小技巧
    推荐取代Visio的中国人的软件——Edraw
    ASP.NET如何防范SQL注入攻击
    软件版本号规定原则
    三层体系结构总结(三)
    .Net工具 .NET文档生成工具2.2
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/14156527.html
Copyright © 2011-2022 走看看