【博学谷学习记录】超强总结,用心分享 | 架构师 Maven学习总结

news2024/11/18 18:34:50

文章目录

    • Maven基本
      • 1.什么是Maven
      • 2.为什么用Maven?
        • (1)jar 包的规模
        • (2) jar 包的来源
        • (3)jar 包之间的依赖关系
      • 3.Maven目录结构
      • 4.maven仓库配置
    • Pom层次
      • Pom文件简介
      • Super POM
    • 依赖管理
      • 1 依赖传递
      • 2 传递性依赖机制
        • 2.1 传递性依赖的依赖范围
        • 2.2 依赖调解

Maven基本

1.什么是Maven

官网:http://maven.apache.org/

Maven是Apache软件基金会唯一维护的一款自动化构建工具,专注于服务Java平台的项目构建和依赖管理。

	Maven是一个强大的Java项目构建工具,基于POM(项目对象模型)文件,可用于项目构建、依赖模块管理和Javadoc生成等。

	Maven 是一种声明式项目管理工具,通过在 POM 中配置 "who","what","where"等信息,即可满足编译、测试、打包、发布等项目构建需求。 

2.为什么用Maven?

(1)jar 包的规模

随着我们使用越来越多的框架,或者框架封装程度越来越高,项目中使用的jar包也越来越多。项目中,一个模块里面用到上百个jar包是非常正常的。

比如下面的例子,我们只用到 SpringBoot、SpringCloud 框架中的三个功能:

Nacos 服务注册发现
Web 框架环境
图模板技术 Thymeleaf

(2) jar 包的来源

这个jar包所属技术的官网。官网通常是英文界面,网站的结构又不尽相同,甚至找到下载链接还发现需要通过特殊的工具下载。

第三方网站提供下载。问题是不规范,在使用过程中会出现各种问题。

jar包的名称
jar包的版本
jar包内的具体细节
而使用 Maven 后,依赖对应的 jar 包能够自动下载,方便、快捷又规范。

(3)jar 包之间的依赖关系

框架中使用的 jar 包,不仅数量庞大,而且彼此之间存在错综复杂的依赖关系。依赖关系的复杂程度,已经上升到了完全不能靠人力手动解决的程度。另外,jar 包之间有可能产生冲突。进一步增加了我们在 jar 包使用过程中的难度。

3.Maven目录结构

Maven 提倡使用一个共同的标准目录结构,Maven 使用约定优于配置的原则,大家尽可能的遵守这样的目录结构,一个使用Maven管理的普通的Java项目,它的目录结构默认如下:

MavenProject
|-- pom.xml maven项目的配置文件。对项目中的所有jar包依赖进行统一管理
|-- src
|-- main
| – java 存放项目源代码
| – resources(可省略) 存放项目配置文件 .xml等
|-- test(可省略)
| – java 存放单元测试源代码
| – resources 存放单元测试资源文件 .xml等
|-- target(由maven生成) 存放所有编译、打包生成的文件
|-- classes 存放项目源代码编译输出的字节码文件
|-- test-classes 存放测试代码编译输出的字节码文件
默认情况下,项目在编译过后,会将 src/main/java编译过后的字节码文件和 src/main/resource 中的文件放在target/classes目录下。

	但是,src/main/java 目录下的非包且非java的文件在编译过后并不会自动被拷贝在 target/classes 目录下,而是会丢失。

	如果我们想要将 src/main/java 目录下的非包且非java的文件也一并拷贝在target/classes 目录下,则需要在 pom.xml 文件的 build 标签下进行配置。

4.maven仓库配置

Maven 仓库是项目中依赖的第三方库

	在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件,Maven 仓库能帮助我们管理构件(主要是JAR),它就是放置所有JAR文件(WAR,ZIP,POM等等)的地方

Pom层次

Pom文件简介

	而 pom.xml 主要描述了项目的基本信息,用于描述项目如何构建,声明项目依赖等等,是项目级别的配置文件,执行任务或目标时,Maven 会在当前目录中查找 POM,然后读取 POM,获取所需的配置信息,然后执行目标。

	pom(project object model)即项目对象模型,maven 把一个项目的结构和内容抽象成一个模型,在 xml 文件中进行声明,以方便进行构建和描述。

Super POM

经过我们前面的学习,我们看到 Maven 在构建过程中有很多默认的设定。例如:源文件存放的目录、测试源文件存放的目录、构建输出的目录……等等。但是其实这些要素也都是被 Maven 定义过的。定义的位置就是:超级 POM。

关于超级 POM,Maven 官网是这样介绍的:

The Super POM is Maven’s default POM. All POMs extend the Super POM unless explicitly set, meaning the configuration specified in the Super POM is inherited by the POMs you created for your projects.

译文:Super POM 是 Maven 的默认 POM。除非明确设置,否则所有 POM 都扩展 Super POM,这意味着 Super POM 中指定的配置由您为项目创建的 POM 继承。

所以我们自己的 POM 即使没有明确指定一个父工程(父 POM),其实也默认继承了超级 POM。就好比一个 Java 类默认继承了 Object 类。

这个POM文件可以在 [Maven Super Pom](Maven Model Builder – Super POM) 找到。

也可以在 本地这个路径找到 $MAVEN_HOME/lib/maven-model-builder-3.8.1.jar!/org/apache/maven/model/pom-4.0.0.xml

  1. repositories

定义了一个名叫 central的repository,value是 ‘https://repo.maven.apache.org/maven2’,可以从这个地址拉下来dependency。

  1. pluginRepositories

默认 plugin的 repositories

  1. build

设置了一些默认的路径,其中还定义了 几个插件,不过Maven官方也提醒,未来的版本会去掉。

.....

2、父 POM
和 Java 类一样,POM 之间其实也是单继承的。如果我们给一个 POM 指定了父 POM,那么继承关系如下图所示:
在这里插入图片描述
3、有效 POM
有效 POM 英文翻译为 effective POM,它的概念是这样的——在 POM 的继承关系中,子 POM 可以覆盖父 POM 中的配置;如果子 POM 没有覆盖,那么父 POM 中的配置将会被继承。按照这个规则,继承关系中的所有 POM 叠加到一起,就得到了一个最终生效的 POM。显然 Maven 实际运行过程中,执行构建操作就是按照这个最终生效的 POM 来运行的。这个最终生效的 POM 就是有效 POM,英文叫effective POM

查看有效 POM:

mvn help:effective-pom

综上所述,平时我们使用和配置的 POM 其实大致是由四个层次组成的:

超级 POM:所有 POM 默认继承,只是有直接和间接之分。
父 POM:这一层可能没有,可能有一层,也可能有很多层。
当前 pom.xml 配置的 POM:我们最多关注和最多使用的一层。
有效 POM:隐含的一层,但是实际上真正生效的一层。

Pom文件构成
一个基本的pom.xml文件配置如下

<?xml version="1.0" encoding="UTF-8"?>



4.0.0

<!-- 公司或者组织的唯一标志,一般是公司域名的倒写,或者是公司域名倒写+项目名。并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group -->
<groupId>org.heima</groupId>

<!-- 项目的唯一ID,一个groupId下面可以有多个项目,通过artifactId来区分 -->
<artifactId>maven_project</artifactId>

<!-- 项目的版本号 -->
<version>1.0-SNAPSHOT</version>
所有 POM 文件都需要 标签元素和该标签下的三个必需字段:groupId,artifactId,version。
	groupId + artifactId + version = 坐标,坐标可用于标识互联网中的唯一资源,在Maven中,坐标是Jar包的唯一标识,Maven通过坐标在仓库中找到项目所需的Jar包。

常见标签
下面我们看下Maven中的常用标签

parent标签
在maven多模块项目中引用父pom依赖,在springboot项目中就有父依赖

org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE

properties标签
定义一些全局属性值,常用于jar包版本定义全局管理jar包版本后面可以${} 取值

	在springboot项目中父pom会定义一些项目jar包版本依赖 ,所以我们在引用jar时候才不用写jar包版本,会自动跟随父pom中定义的jar包版本
org.springframework.boot spring-boot-dependencies 2.4.7

dependencyManagement标签
在Maven多模块的时候,管理依赖关系是非常重要的,各种依赖包冲突,查询问题起来非常复杂,于是就用到了,在springboot项目中父模块就定义了

org.springframework.boot spring-boot 2.2.2.RELEASE org.springframework.boot spring-boot-test 2.2.2.RELEASE org.springframework.boot spring-boot-test-autoconfigure 2.2.2.RELEASE ................................... 那么在子模块中只需要和即可,不需要加入版本号, org.springframework.boot spring-boot-starter-aop 使用dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,不利于管理,当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号

dependencies标签
用于引入项目依赖

org.springframework.boot spring-boot-starter-aop dependencies和dependencyManagement区别 Dependencies相对于dependencyManagement,所有声明在dependencies里的依赖都会自动引入,并默认被所有的子项目继承, 而dependencyManagement里只是声明依赖,并不自动实现引入,因此子项目需要显示的声明需要用的依赖。
	如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

uild标签
在实际使用 Maven 的过程中,我们会发现 build 标签有时候有,有时候没,这是怎么回事呢?其实通过有效 POM 我们能够看到,build 标签的相关配置其实一直都在,只是在我们需要定制构建过程的时候才会通过配置 build 标签覆盖默认值或补充配置。这一点我们可以通过打印有效 POM 来看到。

所以本质上来说:我们配置的 build 标签都是对超级 POM 配置的叠加。那我们又为什么要在默认配置的基础上叠加呢?很简单,在默认配置无法满足需求的时候定制构建过程。

build 标签组成

从示例中我们能够看到,build 标签的子标签大致包含三个主体部分:

① 定义约定的目录结构

参考示例中的如下部分:

<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<resources>
  <resource>
    <directory>${project.basedir}/src/main/resources</directory>
  </resource>
</resources>
<testResources>
  <testResource>
    <directory>${project.basedir}/src/test/resources</directory>
  </testResource>

我们能看到各个目录的作用如下:

目录名 作用
sourceDirectory 主体源程序存放目录
scriptSourceDirectory 脚本源程序存放目录
testSourceDirectory 测试源程序存放目录
outputDirectory 主体源程序编译结果输出目录
testOutputDirectory 测试源程序编译结果输出目录
resources 主体资源文件存放目录
testResources 测试资源文件存放目录
directory 构建结果输出目录

② 备用插件管理

pluginManagement 标签存放着几个插件:

maven-antrun-plugin
maven-assembly-plugin
maven-dependency-plugin
maven-release-plugin
通过 pluginManagement 标签管理起来的插件就像 dependencyManagement 一样,子工程使用时可以省略版本号,起到在父工程中统一管理版本的效果。情看下面例子:

被 spring-boot-dependencies 管理的插件信息:
子工程使用的插件信息:



org.springframework.boot
spring-boot-maven-plugin


③生命周期插件

plugins 标签存放的是默认生命周期中实际会用到的插件,这些插件想必大家都不陌生,所以抛开插件本身不谈,我们来看看 plugin 标签的结构:

maven-compiler-plugin 3.1 default-compile compile compile default-testCompile test-compile testCompile

依赖管理

1 依赖传递

在这里插入图片描述

2 传递性依赖机制

	项目A中,我们为了实现某一个功能通常会引入第三方库,这里是一个compile依赖范围的B依赖,而B依赖同时又依赖于另一个compile依赖范围的C组件。

	那么对A而言,C就是它的一个传递性依赖,在Maven中,其会将我们在POM文件中显式声明的直接依赖(本例的B依赖)引入到项目中,对于必要的间接依赖(本例的C依赖)则会以传递性依赖的形式自动地引入到项目A中,而无需我们手动显式地在POM文件中声明C依赖来引入。

	Maven的传递性依赖机制,大大地减少了人工维护间接依赖的复杂度

2.1 传递性依赖的依赖范围

项目A依赖于B组件,B组件依赖于C组件,则我们将A对于B的依赖称之为第一直接依赖,B对于C的依赖称之为第二直接依赖。

	根据上文可知,A对于C的依赖是传递性依赖,必要的间接依赖C将通过传递性依赖机制,被自动引入到A中。那么如何判定一个间接依赖是否有必要被引入呢?间接依赖被引入后其依赖范围又是什么呢?

	答案其实很简单,就是通过第一直接依赖的依赖范围和第二直接依赖的依赖范围之间的关系,来判定是否有必要引入间接依赖以及确定引入间接依赖后其依赖范围。

	如下表所示,若结果为N,则意味着该传递性依赖为非必要的,无需引入;否则,该间接依赖为必要的并自动引入该间接依赖,且引入后该传递依赖的依赖范围如下表单元格中的文字所示

Maven依赖范围不仅控制依赖与classpath的关系,还会影响依赖传递

	最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间的交叉单元格则表示传递性依赖范围

compile	test	provided	runtime

compile compile N N runtime
test test N N test
provided provided N provided provided
runtime runtime N N runtime
仔细观察上面表格,我们发现这样的规律

当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
当第二直接依赖的范围是test的时候,依赖不会得以传递;
当第二直接依赖的范围是provided的时候,只传递第一直接依赖的范围也为provided的依赖,切传递性依赖的范围同样为provided;
当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile例外,此时传递性依赖的范围为runtime。

2.2 依赖调解

在Maven中由于传递性依赖的机制,一般情况下我们不需要关心间接依赖的管理。

	而当间接依赖出问题时,我们需要知道该间接依赖是通过哪条依赖路径引入的,特别是该间接依赖存在多条引入路径时,确定间接依赖引入的路径就显得尤为重要。当一个间接依赖存在多条引入路径时,为避免依赖重复Maven会通过依赖调解来确定该间接依赖的引入路径

依赖调解遵循以下原则,优先使用第一原则,当第一原则无法解决时,则通过第二原则解决

第一原则: 路径最短者优先
第二原则: 第一声明者优先

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/633894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于51单片机的智能火灾报警系统温度烟雾光

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;火灾报警 获取完整源码源文件电路图仿真文件论文报告等 功能简介 51单片机MQ-2烟雾传感ADC0832模数转换芯片DS18B20温度传感器数码管显示按键模块声光报警模块 具体功能&#xff1a; 1、实时监测及显示温度值和烟雾浓度…

【Docker】docker部署springboot+vue+mysql+nginx前后端分离项目【部署实战篇】

文章目录 0、安装docker并准备一个springboot-vue前后端分离项目前后端打包放到服务器上1、docker 安装jdk2、docker 安装mysql通过Docker命令进入Mysql容器内部初始化数据sqlDbx连接查看 3、docker build构建后端镜像修改配置数据库JDBC链接IP为虚拟机服务器IPmaven clean pac…

【MySQL】一文带你掌握聚合查询和联合查询

文章目录 1. 聚合函数1.1 COUNT1.2 SUM1.3 AVG1.4 MAX&#xff0c;MIN 2. GROUP BY3. HAVING4. 联合查询4.1 内连接4.2 外连接4.3 自连接4.4 子连接 5.合并查询5.1 UNION5.2 UNION ALL 1. 聚合函数 概念&#xff1a; 聚合函数是一种用于处理数据集合的函数&#xff0c;它将多个…

Fiddler 抓包的八个实用技巧,你学会了吗?

目录 前言 1、双击Session时&#xff0c;使响应页始终显示到”json”tab页&#xff1b;使请求页始终显示到“webform”tab页 2、显示每个Session 的请求IP地址 3、修改响应Header中的Content-Type 4、右键session 直接使用浏览器打开url 5、Session列中&#xff0c;显示每…

电脑拷贝到u盘数据丢失原因分析|3种恢复方法

在电脑操作中&#xff0c;经常需要将数据拷贝到U盘中进行备份或传输。但有时候&#xff0c;我们可能会遇到数据在拷贝或传输过程中丢失的情况。这种情况下&#xff0c;我们该如何找回这些丢失的数据呢&#xff1f; 下面&#xff0c;为大家介绍一些恢复U盘数据的方法&#xff0c…

[ICNN 1993] Optimal brain surgeon and general network pruning

Contents IntroductionMethodOptimal brain surgeon (OBS)Computing the inverse HessianThe ( t − o ) → 0 (\mathbf t-\mathbf o)\rightarrow 0 (t−o)→0 Approximation References Introduction 作者提出 Optimal brain damage (OBD) 的改进 Optimal brain surgeon (OB…

霍夫变换(Hough Transform)

文章目录 1. 什么是霍夫变换2. 霍夫直线检测2.1 霍夫直线检测的具体步骤2.2 霍夫直线检测的优缺点2.3 OpenCV中霍夫直线检测的应用2.3.1 标准霍夫检测2.3.2 概率霍夫检测 3. 霍夫圆检测4. 源码仓库地址 1. 什么是霍夫变换 霍夫变换(Hough Transform)是图像处理中的一种特征提取…

Spring Data Redis的使用

Redis的valus值的五种数据类型 问题&#xff1a;Windows下出现Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝&#xff0c;无法连接。 解决方法为在Redis-x64-3.2.100目录下打开两个cmd窗口&#xff0c;分别输入 命令redis-server.exe redis.windows…

【Go知识点】Gorm Hook 无侵入实现 数据表防篡改

一、前言 Hi&#xff0c;开门见山的说&#xff0c;这次给大家带来的是关于 Gorm Hook 机制的落地场景&#xff0c;笔者也是在Gorm官方文档中了解到有Hook机制的存在&#xff0c;不过一直没有找到过太多合适的场景来使用。 最近刚好在做一块新业务的设计&#xff0c;因为涉及到…

PL2303HXA自2012已停产,请联系供货商的解决办法

一、概述 PL2303 是Prolific 公司生产的一种高度集成的接口转换器&#xff0c;可提供一个RS232 全双工异步串行通信装置与USB 功能接口便利连接的解决方案。PL2303具有多个历史版本&#xff0c;早期的版本是PL2303HX, 近年有PL2303HXA、PL2303HXC、PL2303HXD&#xff08;D版本…

SpringCloud01:SpringCloud介绍、服务提供者、服务消费者

SpringCloud和SpringBoot的关系 SpringBoot专注于快速、方便地开发单个个体微服务&#xff0c;SpringCloud关注全局的治理框架&#xff0c;它将SpringBoot开发的一个个单体微服务整合并管理起来&#xff0c;为各个微服务之间提供&#xff1a;管理配置、服务发现、断路器、路由…

GO-slice详解

GO-slice详解 简介 slice&#xff08;切片&#xff09;是go中常见和强大的类型&#xff0c;这篇文章不是slice使用简介&#xff0c;从源码角度来分析slice的实现&#xff0c;slice的一些迷惑的使用方式&#xff0c;同时也讲清楚一些问题。 slice的底层实现是数组&#xff0c…

(转载)基于蚁群算法的三维路径规划(matlab实现)

1 理论基础 1.1 三维路径规划问题概述 三维路径规划指在已知三维地图中&#xff0c;规划出一条从出发点到目标点满足某项指标最优&#xff0c;并且避开了所有三维障碍物的三维最优路径。现有的路径规划算法中&#xff0c;大部分算法是在二维规划平面或准二维规划平面中进行路…

微服务框架

流量入口Nginx 在上图中可以看到&#xff0c;Nginx作为整个架构的流量入口&#xff0c;可以理解为一个外部的网关&#xff0c;它承担着请求的路由转发、负载均衡、动静分离等功能。作为一个核心入口点&#xff0c;Nginx肯定要采用多节点部署&#xff0c;同时通过keepalived来实…

(八)CSharp-泛型类和参数约束(1)

一、C# 中的泛型 泛型&#xff08;generic&#xff09;特性可以让多个类型共享一组代码。 泛型类型不是类型&#xff0c;而是类型的模板。 C# 提供了5种类型&#xff1a;类、结构、接口、委托和方法。 泛型类 泛型的主要优点&#xff1a; 性能 类型转换时&#xff0c;非泛型的…

2018~2019 学年第二学期《信息安全》考试试题(B 卷)

北京信息科技大学 2018 ~2019 学年第 2 学期 《信息安全》课程期末考试试卷 B 课程所在学院:计算机学院 适用专业班级:计科 1601-06&#xff0c;重修 考试形式:(闭卷) 一. 选择题(本题满分 10 分&#xff0c;共含 10 道小题&#xff0c;每小题 1 分) 网络中存在的安全漏洞主…

虚拟环境创建、配置及激活

虚拟环境创建、配置及激活 前言 一、虚拟环境是什么&#xff1f; 虚拟环境&#xff08;Virtual Environment&#xff09;是在计算机上使用特定版本的编程语言&#xff08;如python 3.9&#xff09;和其所需包及依赖项的一种方法(如pandas 2.4)&#xff0c;它可以被看作是一个隔…

基于html+css的图展示121

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

chatgpt赋能python:Python中如何快速删除字符串

Python中如何快速删除字符串 在Python编程中&#xff0c;字符串操作是非常常见的。有时候我们需要从字符串中删除一些无用的字符&#xff0c;以便更方便地处理数据。在本文中&#xff0c;将介绍Python如何快速删除字符串。 删除特定字符 Python中可以使用replace()函数快速替…

【深度学习炼丹大杀器——mlrunner初体验(以mmdetection为例)】

深度学习炼丹大杀器——mlrunner初体验&#xff08;以mmdetection为例&#xff09; 自动化炼丹&#xff0c;告别手动运行的烦恼~ 0.引言 了解深度学习的人都知道&#xff0c;炼丹是一种很玄学的事&#xff0c;并且还存在以下问题&#xff1a; 效率&#xff1a;在训练模型时&…