1、概念

Maven工程之间,A 工程继承 B 工程

  • B 工程:父工程
  • A 工程:子工程

本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。

2、作用

在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
它的背景是:

  • 对一个比较大型的项目进行了模块拆分。
  • 一个 project 下面,创建了很多个 module。
  • 每一个 module 都需要配置自己的依赖信息。

它背后的需求是:

  • 在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
  • 使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
  • 使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。

通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。

3、举例

在一个工程中依赖多个 Spring 的 jar 包
TIP
[INFO] +- org.springframework:spring-core:jar:4.0.0.RELEASE:compile
[INFO] | - commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-expression:jar:4.0.0.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.0.RELEASE:compile
[INFO] | - aopalliance:aopalliance:jar:1.0:compile

使用 Spring 时要求所有 Spring 自己的 jar 包版本必须一致。为了能够对这些 jar 包的版本进行统一管理,我们使用继承这个机制,将所有版本信息统一在父工程中进行管理。

4、操作

①创建父工程

创建的过程和前面创建 pro01-maven-java 一样。
工程名称:pro03-maven-parent
工程创建好之后,要修改它的打包方式:

  1. <groupId>com.atguigu.maven</groupId>
  2. <artifactId>pro03-maven-parent</artifactId>
  3. <version>1.0-SNAPSHOT</version>
  4. <!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
  5. <packaging>pom</packaging>

只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。打包方式为 pom 的 Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。

②创建模块工程

模块工程类似于 IDEA 中的 module,所以需要进入 pro03-maven-parent 工程的根目录,然后运行 mvn archetype:generate 命令来创建模块工程。
假设,我们创建三个模块工程:
image.png

③查看被添加新内容的父工程 pom.xml

下面 modules 和 module 标签是聚合功能的配置

  1. <modules>
  2. <module>pro04-maven-module</module>
  3. <module>pro05-maven-module</module>
  4. <module>pro06-maven-module</module>
  5. </modules>

④解读子工程的pom.xml

  1. <!-- 使用parent标签指定当前工程的父工程 -->
  2. <parent>
  3. <!-- 父工程的坐标 -->
  4. <groupId>com.atguigu.maven</groupId>
  5. <artifactId>pro03-maven-parent</artifactId>
  6. <version>1.0-SNAPSHOT</version>
  7. </parent>
  8. <!-- 子工程的坐标 -->
  9. <!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
  10. <!-- <groupId>com.atguigu.maven</groupId> -->
  11. <artifactId>pro04-maven-module</artifactId>
  12. <!-- <version>1.0-SNAPSHOT</version> -->

⑤在父工程中配置依赖的统一管理

  1. <!-- 使用dependencyManagement标签配置对依赖的管理 -->
  2. <!-- 被管理的依赖并没有真正被引入到工程 -->
  3. <dependencyManagement>
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.springframework</groupId>
  7. <artifactId>spring-core</artifactId>
  8. <version>4.0.0.RELEASE</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework</groupId>
  12. <artifactId>spring-beans</artifactId>
  13. <version>4.0.0.RELEASE</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-context</artifactId>
  18. <version>4.0.0.RELEASE</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.springframework</groupId>
  22. <artifactId>spring-expression</artifactId>
  23. <version>4.0.0.RELEASE</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework</groupId>
  27. <artifactId>spring-aop</artifactId>
  28. <version>4.0.0.RELEASE</version>
  29. </dependency>
  30. </dependencies>
  31. </dependencyManagement>

⑥子工程中引用那些被父工程管理的依赖

关键点:省略版本号,如果不省略,子工程会覆盖父工程的版本

  1. <!-- 子工程引用父工程中的依赖信息时,可以把版本号去掉。 -->
  2. <!-- 把版本号去掉就表示子工程中这个依赖的版本由父工程决定。 -->
  3. <!-- 具体来说是由父工程的dependencyManagement来决定。 -->
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.springframework</groupId>
  7. <artifactId>spring-core</artifactId>
  8. </dependency>
  9. <dependency>
  10. <groupId>org.springframework</groupId>
  11. <artifactId>spring-beans</artifactId>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.springframework</groupId>
  15. <artifactId>spring-context</artifactId>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.springframework</groupId>
  19. <artifactId>spring-expression</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework</groupId>
  23. <artifactId>spring-aop</artifactId>
  24. </dependency>
  25. </dependencies>

⑦在父工程中升级依赖信息的版本

  1. ……
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-beans</artifactId>
  5. <version>4.1.4.RELEASE</version>
  6. </dependency>
  7. ……

然后在子工程中运行mvn dependency:list,效果如下:
TIP
[INFO] org.springframework:spring-aop:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-core:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-context:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-beans:jar:4.1.4.RELEASE:compile
[INFO] org.springframework:spring-expression:jar:4.1.4.RELEASE:compile

⑧在父工程中声明自定义属性

  1. <!-- 通过自定义属性,统一指定Spring的版本 -->
  2. <properties>
  3. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  4. <!-- 自定义标签,维护Spring版本数据 -->
  5. <!-- 标签名:属性名 -->
  6. <!-- 标签值:属性值 -->
  7. <!-- 引用方式:${atguigu.spring.version} -->
  8. <atguigu.spring.version>4.3.6.RELEASE</atguigu.spring.version>
  9. </properties>

在需要的地方使用${}的形式来引用自定义的属性名:

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-core</artifactId>
  4. <version>${atguigu.spring.version}</version>
  5. </dependency>

真正实现“一处修改,处处生效”。

5、实际意义

第九节 实验九:继承 - 图2
编写一套符合要求、开发各种功能都能正常工作的依赖组合并不容易。如果公司里已经有人总结了成熟的组合方案,那么再开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。
如上图所示,公司级的父工程中管理的就是成熟的依赖组合方案,各个新项目、子系统各取所需即可。