持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
1.继承的概念
一个maven工程是可以继承另一个maven工程的,类似于Java里面类的继承。比方说,Maven工程A可以继承Maven工程B,继承的本质其实是让Maven工程A的pom文件的配置继承了Maven工程B的pom文件的配置。这时我们也称B为父工程,A为子工程。
2.继承的作用
继承的作用在于可以在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。
有同学可能会有疑问,为什么我们需要让父工程来统一管理依赖信息。我们设想一下,我们现在有一个电商项目,这个电商项目很大,我们需要将它分成多个模块来进行开发,比如:订单模块、库存模块、物流模块等。如果我们各个模块各自维护自己的依赖,那么就容易导致依赖信息出现出入,不易管理。这个电商模块是在同一框架里面的,使用同一框架的不同jar包应该是同一版本,所以整个项目使用的框架应该统一。使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。
综上所述,我们采用父工程来进行同一版本管理的好处是:
- 可以保证jar版本的统一
- 让项目规范
- 可以将这些经验保留下来,下次再次使用
3.继承实例
我们刚刚讲述了什么是继承,以及继承的作用,那么具体是如何体现出来的呢?我们接下来创建一个父工程pro03-maven-parent,在这个工程里面创建pro04-maven-module,pro05-maven-module,pro06-maven-module三个子工程。
3.1 创建父工程
当工程创建好之后,我们第一件要做的事情是修改它的打包方式。将打包方式改为pom,不然它无法成为一个父工程,无法在里面创建子模块。
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--当前工程作为父工程,要去管理其它工程,打包方式必须是 pom-->
<packaging>pom</packaging>
注意:只有打包方式为 pom 的 Maven 工程能够管理其他 Maven 工程。打包方式为 pom 的 Maven 工程中不写业务代码,它是专门管理其他 Maven 工程的工程。
3.2 创建子项目(模块工程)
创建结果如下图所示:
让我们把目光重新回到父工程的pom文件,你会发现多出来如下内容:
<!--聚合的配置-->
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
那子模块的pom文件是否也包含了父工程的信息?答案是肯定的。我们查看其中一个子模块,内容如下:
<!-- parent 标签,给当前工程配置父工程-->
<parent>
<groupId>com.atguigu.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--子工程的 groupId 如果和父工程一样,则可以省略-->
<!--<groupId>com.atguigu.maven</groupId>-->
<!--子工程的 version 如果和父工程一样,则可以省略-->
<!-- <version>1.0-SNAPSHOT</version>-->
<!--省略groupId和version后,子工程自己的坐标可以只保留artifactId-->
<artifactId>pro04-maven-module</artifactId>
注意:如果子工程的groupId和version父工程一样,那是可以省略的,artifactId就不能省略了。
3.3 在父工程进行依赖的统一管理
我们需要用一个标签dependencyManagement。将依赖都放到这个标签里面,如下
<!-- 使用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>
在父工程里配置好了依赖信息,并不意味着子工程就拥有了这些依赖。子工程需要自己决定需要父工程里面的哪些依赖。你看,pro04-maven-module里面没有任何父工程的依赖。
接下来,在pro04-maven-module的pom文件里面配置想要的父工程的依赖。
<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-->
<!--<version>4.0.0.RELEASE</version>-->
<!--情况1 确实省略了 version 标签:子工程采纳的就是父工程管理的版本-->
<!--情况2 没有 version 标签:
A:这里配置了 version 和父工程管理的版本一致,最终还是采纳这个版本
B: 这里配置了 version
但是和父工程管理的版本不一致,那么这里子工程配置的版本会覆盖父工程管理的版本并最终采纳。
绝大部分情况下子工程还是遵从父工程统一管理的依赖。
-->
</dependency>
</dependencies>
我们看下结果:
3.4 升级父工程依赖
如果我们升级父工程的依赖,那么对应的引用了该依赖的子模块的依赖也会升级
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!--<version>4.0.0.RELEASE</version>-->
<version>4.3.16.RELEASE</version>
</dependency>
我们看下父工程依赖升级后,子项目的依赖是否也跟着升级了。
我们可以发现升级了。
3.5 在父工程中声明自定义属性
在3.4节中,我们修改依赖的版本信息是手动找到对应的依赖,然后修改。如果只有一个依赖的版本需要修改这样显然没什么问题,要是信息多了呢?这时,我们可以借助properties标签来自定属性。atguigu.spring.version这个标签使我们自己定义的。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--创建我们自定义的属性标签-->
<!--标签名:属性名-->
<!--标签值:属性值-->
<!--引用方式:${atguigu.spring.version} -->
<atguigu.spring.version>4.3.16.RELEASE</atguigu.spring.version>
</properties>
<!--聚合的配置-->
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
<!-- 在父工程中统一管理依赖信息-->
<!--注意:即使在父工程配置了对依赖的管理,子工程需要使用具体哪一个依赖还是要明确配置。-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<!--<version>4.0.0.RELEASE</version>-->
<version>${atguigu.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<!--通过引用属性表达式设定版本号,这样版本号就成了一个动态值-->
<!--通过属性名解析后才知道具体是什么值-->
<version>${atguigu.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${atguigu.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${atguigu.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${atguigu.spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
我们来看下实验结果
4.聚合
聚合其实刚刚看过了,就是父工程的这个
<!--聚合的配置-->
<modules>
<module>pro04-maven-module</module>
<module>pro05-maven-module</module>
<module>pro06-maven-module</module>
</modules>
4.1 聚合的实际意义
继承的实际作用除了能让父工程来进行统一的版本管理之外,还能将项目经验积累下来,以后要是有别的项目,可以直接沿用上次的父工程配置。毕竟一套可用的配置需要较长时间的摸索。
4.2 聚合在实际项目中的好处
一键执行 Maven 命令:很多构建命令都可以在“总工程”中一键执行。 比方说,你可以在总工程里面运行install,那么各子模块也会运行这命令。对了,如果你的项目有依赖关系,比如父工程是A,里面的子工程B,C,D之间有依赖关系,如B依赖C,C依赖D。当你在父工程执行install命令的时候,你不用自己考虑install的顺序,在总工程install,会先帮你install D,接着C,最后B。
我们要注意下,不要出现循环依赖,如B依赖C,C依赖D,D依赖B。不然会报错。
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference: