IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Maven的依赖(Dependency) -> 正文阅读

[Java知识库]Maven的依赖(Dependency)

背景

在Maven世界里,每一个构件(artifact)都有一个唯一的坐标(Coordinate)。坐标是用一系列元素来定义的:

  • groupId
  • artifactId
  • version
  • packaging
  • classifier

其中, groupIdartifactIdversion 是必需的,packaging是可选的(默认值为 jar ),而classifier是不能直接定义的。

问题

在pom文件中,我们可以定义依赖关系,例如:

............
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		............
	<dependencies>
............

被依赖的artifact(本例中是 spring-boot-starter-web ),显然也需要 groupIdartifactIdversion 来唯一标识,然而,这里只有 groupIdartifactId ,并没有 version 。这是怎么回事呢?

带着这个问题,我们来看一下Maven的依赖(dependency)。

聚合和继承

一个项目(project)的开发,通常采用“模块化开发”的方式,项目是由多个模块(module)所组成。模块秉承“高内聚,低耦合”的原则,例如开发团队分为多个小组,每组只专注于各自所负责的模块的开发和调试。但项目作为一个整体,需要在总体上进行构建。

Maven提供了 聚合继承 这两个概念:

  • 聚合:把各个模块聚合在一起构建;
  • 继承:抽取各个模块相同的依赖和插件等配置,以简化配置,方便维护;

聚合

聚合比较简单,就是把多个模块在一起构建。例如,我们有 module1module2 两个模块。为了把它们聚合在一起,我们再创建一个额外的 aggregator 模块。该模块本身作为一个Maven项目,有自己的pom文件,但是它不涉及项目的具体业务逻辑,所以没有src等目录。

<?xml version="1.0" encoding="UTF-8"?>
<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>com.example.demo0402</groupId>
	<artifactId>aggregator</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Aggregator</name>
	<modules>
		<module>module1</module>
		<module>module2</module>
	</modules>
</project>

该pom文件的核心配置是:

  • packaging :必须是 pom
  • modules :要聚合的模块。注意此处的每一个值都是针对当前pom文件的相对路径。通常可以令目录名与其artifact名一致,以便于理解和快速定位,不过也不强制,反正记住这里要写目录名;

一般我们把聚合模块作为module1、module2等模块的父一级目录,即:

?  test0402 tree
.
└── aggregator
    ├── module1
    │   ├── pom.xml
    │   └── src
    │       ├── main
    │       │   ├── java
    │       │   └── resources
    │       └── test
    │           └── java
    ├── module2
    │   ├── pom.xml
    │   ├── src
    │   │   ├── main
    │   │   │   ├── java
    │   │   │   └── resources
    │   │   └── test
    │   │       └── java
    └── pom.xml

在做build的时候,可以看到构建的细节,例如:

?  aggregator mvn clean install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] module1                                                            [jar]
[INFO] module2                                                            [jar]
[INFO] Aggregator                                                         [pom]
............
[INFO] Reactor Summary for Aggregator 0.0.1-SNAPSHOT:
[INFO] 
[INFO] module1 ............................................ SUCCESS [ 11.691 s]
[INFO] module2 ............................................ SUCCESS [  4.185 s]
[INFO] Aggregator ......................................... SUCCESS [  0.060 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  16.123 s
[INFO] Finished at: 2022-04-03T17:48:02+08:00
[INFO] ------------------------------------------------------------------------

注意上面显示的是各个模块的 name ,而不是 artifactId

继承

module1module2 模块有很多相同的配置,比如 groupIdversion ,此外还有 spring-boot-starter-web 等三方依赖包也一样。重复的配置显然增加了维护成本,并带来潜在的不一致风险。

Maven提供了继承机制,来抽取重复的配置。这有点类似于面向对象的父子类关系,在父POM中定义一些配置以供子POM来继承。

“父POM”与“聚合POM”有些相似之处:

  • packaging 必须为 pom
  • 不需要src目录;

aggregator 目录下创建 parent 目录,然后在 parent 目录里创建 pom.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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>com.example.demo0402</groupId>
	<artifactId>parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>
	<name>Parent</name>
</project>

有了父模块, module1module2 还必须显式的声明继承关系。

以module1为例,在其pom.xml文件中添加如下内容:

	<parent>
		<groupId>com.example.demo0402</groupId>
		<artifactId>parent</artifactId>
		<version>0.0.1-SNAPSHOT</version>
		<relativePath>../parent/pom.xml</relativePath>
	</parent>

module1 可以删除自己的 groupIdversio 设置,默认会从父模块继承。这样,各个模块保持相同的groupId和version。

注: relativePath 的默认值是 ../pom.xml ,即上一级目录

接下来,我们来把dependency抽取到父模块。

若直接把module1和module2公共的dependency配置直接移到父模块,固然OK,不过这种做法存在一个问题,如果以后再有module3,而module3并不需要这些dependency,这就难办了。

所以Maven提供了 dependencyManagement 元素。在父模块中通过 dependencyManagement 元素声明dependency,而在子模块中通过 dependency 元素引用所需的dependency。

在父模块POM中添加如下内容:

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-web</artifactId>
				<version>2.6.6</version>
			</dependency>
		</dependencies>
	</dependencyManagement>

在子模块POM的 dependencies 中添加如下内容:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

可见,子模块的dependency只需指明 groupIdartifactId ,而无需指定 version 。这是因为完整的dependency信息是在父模块的 dependencyManagement 定义的,所以子模块只需通过 groupIdartifactId 来引用即可。

这种做法的好处是:

  • 统一性:所有dependency都由父模块统一定义,确保子模块使用的dependency版本一致;
  • 灵活性:子模块只需引用自己所需的dependency;

有一种特殊的依赖范围,叫做 import 。这种依赖通常指向一个POM,作用是将其 dependencyManagement 配置导入到当前的POM中。例如:

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.example.demo0402</groupId>
				<artifactId>xxx</artifactId>
				<version>0.0.1-SNAPSHOT</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>com.example.demo0402</groupId>
				<artifactId>yyy</artifactId>
				<version>0.0.1-SNAPSHOT</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			............
		</dependencies>
	</dependencyManagement>

常见做法是把依赖根据类型不同,生成多个POM(如上例中的 xxxyyy 等),然后在父模块中将其导入,以便“分而治之”。

聚合与继承的关系

共同点

  • packaging 必须是 pom
  • 除了POM外并无src等实际内容;

区别

  • 聚合:为了方便快速构建整个项目。聚合POM知道被聚合的POM,而被聚合的POM不知道聚合POM;
  • 继承:为了消除重复配置。父POM不知道子POM,子POM知道父POM;

集成

为了方便,通常可以把聚合POM和父POM合二为一,只用一个POM。具体例子参见代码。

代码

https://github.com/dukeding/test0402

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 11:57:15  更:2022-04-04 11:57:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:02:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码