Maven 工程之间的继承
文章目录
1. 概念
Maven工程之间,A 工程继承 B 工程
- B 工程:父工程
- A 工程:子工程
本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。
2. 作用
在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
它的背景是:
- 对一个比较大型的项目进行了模块拆分。
- 一个 project 下面,创建了很多个 module。
- 每一个 module 都需要配置自己的依赖信息。
它背后的需求是:
- 在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
- 使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
- 使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
3. 举例
在一个工程中依赖多个 Spring 的 jar 包
[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 包的版本进行统一管理,我们使用继承这个机制,将所有版本信息统一在父工程中进行管理。
继承的版本管理的注意点:
- 所继承的父工程的包方式:一定要为:
<packaging>pom</packaging>
才能管理其他工程。 - 子工程当中的 依赖的
jar
不要写明版本,才会继承父工程当中的版本信息配置。如果子工程写明了对应的jar
的版本,则不会继承父工程的版本信息配置,而是根据子工程自己的版本信息配置的。
4. 操作
①创建父工程
创建的过程和前面创建 pro01-maven-java 一样。
工程名称:pro03-maven-parent
如下:
E:\Maven_workspane\spaceVideo>mvn archetype:generate
工程创建好之后,要在pom.xml
配置文件当中修改, 它的打包方式:为 pom
才能作为父工程,管理其他的工程。
<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>com.rainbowSea.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--当前工程作为父工程,要去管理其他工程:打包方式必须为 pom 才行-->
<packaging>pom</packaging>
<name>pro03-maven-parent</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。打包方式为 pom 的 Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。
②创建模块工程
模块工程类似于 IDEA 中的 module,所以需要进入 pro03-maven-parent 工程的根目录,然后运行 mvn archetype:generate 命令来创建模块工程。
就是把 pr03-maven-parent 作为父工程,在其下面创建其子工程:
假设,我们创建三个模块工程:
这里我们就简单的创建两个子工程吧:分别为:pro04-maven-module,pro05-maven-module
执行如下创建 Mavne 工程命令
mvn archetype:generate
③查看被添加新内容的父工程 pom.xml
当我们在 pro03-maven-parent 父工程下创建了,两个子工程的时候。
我们在回到 pro03-maven-parent父工程下,查看其 pom.xml
发生了什么要的改变。
我们可以看到在 该 pro03-maven-parent父工程下的 pom.xml 配置文件当中,多添加了,如下:信息:
下面 modules 和 module 标签是聚合功能的配置
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
</modules>
④解读子工程的pom.xml
而我们再,看看,我们对应之下的,pro04-maven-module,pro05-maven-module 的 pom.xml
的配置文件信息,有存在着一个怎样的变化。
<!-- 使用parent标签指定当前工程的父工程 -->
<parent>
<!-- 通过:指定父工程的坐标,找到父工程 -->
<groupId>com.rainbowSea.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的坐标 -->
<!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
<!-- <groupId>com.rainbowSEa.maven</groupId> -->
<artifactId>pro05-maven-module</artifactId>
<!-- <version>1.0-SNAPSHOT</version> -->
⑤在父工程中配置依赖的统一管理子工程
**注意:**即使在父工程配置了对依赖的管理,子工程需要使用依赖时,依旧是要指明/写明具体哪一个依赖的配置的,而不是不用写依赖的配置了,只是可以不用写依赖的版本号了而已。不然子工程当中的所支持的依赖的版本与父工程的版本不一致,子工程还是要指明所对应可以支持的版本号的,因为父工程所继承而来的版本号,自己子工程不支持吗,所以需要自己写明。
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程
注意:即使在父工程配置了对依赖的管理,子工程需要使用依赖时,依旧是要指明/写明具体哪一个依赖的配置的,而不是不用写依赖了。-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
pro03-maven-parent 父工程下的 pom.xml 的全部信息
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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>com.rainbowSea.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--当前工程作为父工程,要去管理其他工程:打包方式必须为 pom 才行-->
<packaging>pom</packaging>
<name>pro03-maven-parent</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程
注意:即使在父工程配置了对依赖的管理,子工程需要使用依赖时,
依旧是要指明/写明具体哪一个依赖的配置的,而不是不用写依赖了。-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
</modules>
</project>
⑥子工程中引用那些被父工程管理的依赖
关键点:省略版本号,如果没有省略版本号,则不会继承父工程下的版本号,而是沿用自己子工程配置的版本号信息。
**注意:**即使在父工程配置了对依赖的管理,子工程依旧需要自己配置要使用的依赖信息,只是省略了版本号而已,其他的还是要子工程自己配置哪个依赖的,父工程的依赖并不会被子工程所继承的
如下是:pr04-maven-module 的配置:
<!-- 子工程引用父工程中的依赖信息时,可以把版本号去掉。 -->
<!-- 把版本号去掉就表示子工程中这个依赖的版本由父工程决定。 -->
<!-- 具体来说是由父工程的 <dependencyManagement>来决定。 -->
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.rainbowSea.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.rainbowSea.maven</groupId>
<artifactId>pro04-maven-module</artifactId>
<version>1.0-SNAPSHOT</version>
<name>pro04-maven-module</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!--即使在父工程配置了对依赖的管理,子工程依旧需要自己配置要使用的依赖信息,只是省略了
版本号而已,其他的还是要子工程自己配置哪个依赖的,父工程的依赖并不会被子工程所继承的-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
</dependencies>
</project>
如下是:pr05-maven-module 的配置:
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.rainbowSea.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.rainbowSea.maven</groupId>
<artifactId>pro05-maven-module</artifactId>
<version>1.0-SNAPSHOT</version>
<name>pro05-maven-module</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
</dependencies>
</project>
运行:mvn dependency:list
命令查看:父工程和子工程的依赖信息配置。
如下是:父工程的
如下是:pro04-maven-module 子工程的
如下是:pro05-maven-module 子工程的:
⑦在父工程中升级依赖信息的版本
将其中的版本修改为 : 4.1.4 版本在运行看看:
……
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
……
父工程下的:
子工程下的:
然后在子工程中运行mvn dependency:list,效果如下:
[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
⑧在父工程中声明自定义属性
我们可以通过父工程当中声明自定义属性:真正实现“一处修改,处处生效”。
就是将父工程的当的各个版本信息配置为一个变量:使用:在 标签当中,配置自定义标签。
自定义的标签,没有特别的要求:不要使用中文,尽量与你配置的哪个 jar 有所关联,做到见明知其是依赖的是哪个 jar包的版本信息。如下:自定义标签,维护Spring版本数据
<!-- 通过自定义属性,统一指定Spring的版本 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 自定义标签,维护Spring版本数据 -->
<rainbowSea.spring.version>4.0.0.RELEASE</rainbowSea.spring.version>
</properties>
使用到该版本信息的的地方使用${}
的形式来引用自定义的属性名:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${rainbowSea.spring.version}</version>
</dependency>
真正实现“一处修改,处处生效”。
运行:mvn dependency:list
命令查看:父工程和子工程的依赖信息配置。
父工程下的:
5. 实际意义
编写一套符合要求、开发各种功能都能正常工作的依赖组合并不容易。如果公司里已经有人总结了成熟的组合方案,那么再开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。
如上图所示,公司级的父工程中管理的就是成熟的依赖组合方案,各个新项目、子系统各取所需即可。
6. 最后:感谢
该文章参考了,如下博主的分享。我们再此,真诚的感谢博主的技术的热情的分享。
⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐感谢如下博主的分享 ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
【1】:兵器|代码重工