type
status
date
slug
summary
tags
category
icon
password
一 Maven简介
为什么需要Maven?
- maven 是一个依赖管理工具(管理规模庞大的 jar 包,需要专门工具)
- jar 包的规模
- 随着我们使用越来越多的框架,或者框架封装程度越来越高,项目中使用的jar包也越来越多。项目中,一个模块里面用到上百个jar包是非常正常的。
- 比如下面的例子,我们只用到 SpringBoot、SpringCloud 框架中的三个功能Nacos 服务注册发现;Web 框架环境;视图模板技术 Thymeleaf;最终却导入了 106 个 jar 包.
- 而如果使用 Maven 来引入这些 jar 包只需要配置三个『依赖』:
- jar包的来源问题
- 这个jar包所属技术的官网。官网通常是英文界面,网站的结构又不尽相同,甚至找到下载链接还发现需要通过特殊的工具下载
- 第三方网站提供下载。问题是不规范,在使用过程中会出现各种问题。
- jar包的名称
- jar包的版本
- jar包内的具体细节
- 而使用 Maven 后,依赖对应的 jar 包能够自动下载,方便、快捷又规范。
- jar包的导入问题
- 在web工程中,jar包必须存放在指定位置:
- 在使用Maven之后,通过配置依赖(jar包)的坐标,查找本地仓库中相应jar包,若本地仓库没有,则统一从镜像网站或中央仓库中下载:
- jar包之间的依赖
- 框架中使用的 jar 包,不仅数量庞大,而且彼此之间存在错综复杂的依赖关系。依赖关系的复杂程度,已经上升到了完全不能靠人力手动解决的程度。另外,jar 包之间有可能产生冲突。进一步增加了我们在 jar 包使用过程中的难度。
- 下面是前面例子中 jar 包之间的依赖关系:
- 而实际上 jar 包之间的依赖关系是普遍存在的,如果要由程序员手动梳理无疑会增加极高的学习成本,而这些工作又对实现业务功能毫无帮助。而使用 Maven 则几乎不需要管理这些关系,极个别的地方调整一下即可,极大的减轻了我们的工作量。
- maven是一个构建工具.(脱离 IDE 环境执行构建操作,需要专门工具)
- 没有注意到的构建
- 你可以不使用 Maven,但是构建必须要做。当我们使用 IDEA 进行开发时,构建是 IDEA 替我们做的.对外提供的,运行的jar包,或者部署到tomcat 中的 war 包都是通过源码构建出来的.
- 脱离 IDE 环境仍需要构建
Maven介绍
- 官网‣
- Maven 是一款为 Java 项目管理构建、依赖管理的工具(软件),使用 Maven 可以自动化构建、测试、打包和发布项目,大大提高了开发效率和质量。
- Maven就是一个软件,掌握安装、配置、以及基本功能 (项目构建、依赖管理) 的理解和使用即可!
- 依赖管理:Maven 可以管理项目的依赖,包括自动下载所需依赖库、自动下载依赖需要的依赖并且保证版本没有冲突、依赖版本管理等。通过 Maven,我们可以方便地维护项目所依赖的外部库,避免版本冲突和转换错误等,而我们仅仅需要编写配置即可。
- 构建管理:项目构建是指将源代码、配置文件、资源文件等转化为能够运行或部署的应用程序或库的过程; Maven 可以管理项目的编译、测试、打包、部署等构建过程。通过实现标准的构建生命周期,Maven 可以确保每一个构建过程都遵循同样的规则和最佳实践。同时,Maven 的插件机制也使得开发者可以对构建过程进行扩展和定制。主动触发构建,只需要简单的命令操作即可。
- 应用场景
- 依赖导入
- 项目构建
- 依赖分享
- 自动部署
场景:例如我们项目需要第三方依赖如:Druid连接池、MySQL数据库驱动和Jackson JSON等处理。那么我们可以将想要的依赖项的信息编写到Maven工程的配置文件,Maven就会自动下载并复制这些依赖项到项目中,无需自己导入jar包,管理jar!
项目完成开发,我们想要打成war部署到服务器中,使用maven的构建命令可以快速打包!节省大量时间!
- maven 软件工作原理原型图
二 Maven安装和配置
- ‣
- 各个工具选用版本:
工具 | 版本 |
Maven | 3.8.8 |
JDK | 17 |
IDEA | 2022.2 |
安装
- 安装条件: maven需要本机安装java环境、必需包含java_home环境变量
- 软件解压:没有中文,没有空格的目录
- 软件结构
- bin:含有Maven的运行脚本
- boot:含有plexus-classworlds类加载器框架
- conf:含有Maven的核心配置文件,主要配置 settings.xml
- lib:含有Maven运行时所需要的Java类库
- LICENSE、NOTICE、README.txt:针对Maven版本,第三方软件等简要介绍
- 环境配置(mac 和 win 不一样,安装时候可自行搜索具体的安装步骤)
- 命令测试(cmd or terminal)
- mvn -v 输出版本信息即可
功能配置
- 需要需改maven/conf/settings.xml配置文件,来修改maven的一些默认配置。我们主要修改的有三个配置:
- 依赖本地缓存位置(本地仓库位置)
- maven下载镜像(镜像源,例:阿里镜像地址)
- maven选用编译项目的jdk版本
- idea 配置本地 maven
- 需要将配置好的maven软件,配置到idea开发工具中即可! 注意:idea工具默认自带maven配置软件,但是因为没有修改配置,建议替换成本地配置好的maven!
- 选择本地软件
- 注意:
- 如果本地仓库地址不变化,只有一个原因,就是maven/conf/settings.xml配置文件编写错误!仔细检查即可!
- 一定保证User settings file对应之前修改的settings.xml的路径,若 不一致,选中Override复选框,手动选择配置文件
三 基于IDEA创建Maven工程
概念梳理Maven工程的GAVP
- Maven工程相对之前的项目,多出一组gavp属性,gav需要我们在创建项目的时候指定,p有默认值.
- Maven 中的 GAVP 是指 GroupId(组织id)、ArtifactId(工程的模块id)、Version(当前工程的版本号)、Packaging(打包方式) 等四个属性的缩写,其中前三个是必要的,而 Packaging 属性为可选项。这四个属性主要为每个项目在maven仓库中做一个标识,类似人的姓-名!有了具体标识,方便后期项目之间相互引用依赖等!
- GAV遵循一下规则:
- GroupID 格式:com.{公司/BU }.业务线.[子业务线],最多 4 级。说明:{公司/BU} 例如:alibaba/taobao/tmall/aliexpress 等 BU 一级;子业务线可选。正例:com.taobao.tddl 或 com.alibaba.sourcing.multilang
- ArtifactID 格式:产品线名-模块名。语义不重复不遗漏,先到仓库中心去查证一下。正例:tc-client / uic-api / tair-tool / bookstore
- Version版本号格式推荐:主版本号.次版本号.修订号(我们现在开发的时候一般都直接递增,没有严格按照这个处理)
- 主版本号:当做了不兼容的 API 修改,或者增加了能改变产品方向的新功能
- 次版本号:当做了向下兼容的功能性新增(新增类、接口等)。
- 修订号:修复 bug,没有修改方法签名的功能加强,保持 API 兼容性。
- packaging 属性为 jar(默认值),代表普通的Java工程,打包以后是.jar结尾的文件.
- packaging 属性为 war,代表Java的web工程,打包以后.war结尾的文件.
- packaging 属性为 pom,代表不会打包,用来做继承的父工程。
例如: 初始→1.0.0 修改bug → 1.0.1 功能调整 → 1.1.1等
d. Packaging定义规则:指示将项目打包为什么类型的文件,idea根据packaging值,识别maven项目类型!
IDEA构建Maven Java SE工程
- 注意:此处省略了version,直接给了一个默认值:1.0-SNAPSHOT,打包方式也可在文件中继续配置.上边这些自己后期可以在项目中随意修改!
- 创建工程之后,若第一次使用maven,或者使用的是新的本地仓库,idea右下角会出现以下进度条,表示maven正在下载相关插件,等待下载完毕,进度条消失即可
- 验证maven工程是否创建成功,当创建完毕maven工程之后,idea中会自动打开Maven视图,如下图:
profiles依赖于本地的配置文件,那propertites什么时候生效呢?作用呢? todo
IDEA构建Maven Java Web工程
- 手动创建的方式
- 创建一个maven的javase工程
- 修改pom.xml文件打包方式,修改位置:项目下/pom.xml
- 设置web资源路径和web.xml路径.点击File-->Project Structure
- 刷新和校验
- 插件创建
- 安装插件JBLJavaToWeb;file/settings/plugins/marketplace
- 创建一个javasemaven工程
- 右键、使用插件快速补全web项目
- 通过maven archetype来创建(生成的web.xml版本比较低)
Maven工程项目结构说明
Maven 是一个强大的构建工具,它提供一种标准化的项目结构,可以帮助开发者更容易地管理项目的依赖、构建、测试和发布等任务。以下是 Maven Web 程序的文件结构及每个文件的作用:
四 基于IDEA进行Maven工程构建
构建概念和构建过程
- 项目构建是指将源代码、依赖库和资源文件等转换成可执行或可部署的应用程序的过程,在这个过程中包括编译源代码、链接依赖库、打包和部署等多个步骤。
- 项目构建是软件开发过程中至关重要的一部分,它能够大大提高软件开发效率,使得开发人员能够更加专注于应用程序的开发和维护,而不必关心应用程序的构建细节。
- 同时,项目构建还能够将多个开发人员的代码汇合到一起,并能够自动化项目的构建和部署,大大降低了项目的出错风险和提高开发效率。常见的构建工具包括 Maven、Gradle、Ant 等。
命令方式项目构建
- mvn的命令必须在pom所在的目录下使用, 要执行多个命令后面跟着就行 mvn clean test (执行 清理 + test)
命令 | 描述 |
mvn compile | 编译项目,生成target文件(只编译核心代码,不会编译test) |
mvn package | 打包项目,生成jar或war文件(包名就是artifactId + 版本 + jar or war) ;生成的包是不包含测试相关的代码和文件;打包之前会执行编译,测试的流程,然后打包 |
mvn clean | 清理编译或打包后的项目结构(清理target[target目录和src属于同级]) |
mvn install | 打包后上传到maven本地仓库 |
mvn deploy | 只打包,上传到maven私服仓库 |
mvn site | 生成站点 |
mvn test-compile | 编译测试代码 |
mvn test | 执行测试源码[
假设我们有一个简单的 Java 项目,其中有src/main/java目录下的主代码和src/test/java目录下的测试代码。
当执行mvn test时,Maven 首先会查找项目的pom.xml文件。这个文件包含了项目的配置信息,如依赖关系等。
接着,它会检查主代码是否已经编译。如果没有编译,会先执行compile阶段,将src/main/java中的 Java 代码编译成字节码,并存放在target/classes目录下。
然后,进入test阶段,它会先执行test - compile,将src/test/java中的测试代码编译成字节码,并存放在target/test - classes目录下。
最后,Maven 会使用测试框架(如 JUnit 或 TestNG)来执行测试类中的测试方法。这些测试方法通常是带有@Test注解(对于 JUnit 5 来说是org.junit.jupiter.api.Test注解)的方法,测试结果会在控制台显示,并且 Maven 会根据测试结果来判断构建是否成功。如果所有测试方法都通过,构建成功;如果有测试方法失败,构建失败。
所以,mvn test会先编译测试代码,然后执行测试代码中的测试方法。
] |
编写规范
- 命名规范(不规范执行命令的时候有可能要不到)
- 测试类命名:通常以被测试类名加上
Test
后缀命名。例如,如果被测试类是Calculator
,则测试类可以命名为CalculatorTest
。[路径和包名也要保持一致]
- 测试方法命名:应描述性强,通常采用
should
+行为描述
+when
+条件描述
的格式。例如: shouldReturnSumWhenAddTwoNumbers
shouldThrowExceptionWhenDivideByZero
- 或者test + 方法名
b. 测试内容
- 单一职责:每个测试方法应该只测试一个逻辑单元或功能,确保它的行为是独立的。
- 预期结果:测试方法应明确指出预期的结果,以便于快速识别测试失败的原因。
- 边界条件:除了测试正常情况外,还应测试边界条件、异常情况和极端值等,确保代码的健壮性。
c. 使用断言
- 选择合适的断言:使用适合的断言方法来验证结果,比如
assertEquals
、assertTrue
、assertFalse
等。尽量使用更具体的断言,避免使用过于宽泛的断言。
- 自定义消息:在断言中添加自定义错误消息,以便于在测试失败时提供更多上下文信息。
d. 测试隔离
- 独立性:每个测试方法应相互独立,确保一个测试的执行不会影响其他测试。可以通过在每个测试方法前设置和清理数据来实现。
- 使用 Mock 对象:当测试依赖于外部系统(如数据库或API)时,使用 Mock 对象模拟这些依赖,以提高测试的可靠性和速度。
e. 编写清晰的测试代码
- 注释:在复杂的测试代码中添加适当的注释,说明测试的意图和逻辑。
- 结构清晰:保持测试代码的结构清晰,使用适当的空行和缩进,以提高可读性。
f. 测试覆盖率
- 高覆盖率:尽量保证高测试覆盖率,但并不意味着要追求 100% 的覆盖率。关键是测试逻辑路径和边界情况。
- 定期审查和重构:定期审查和重构测试代码,以确保其与主代码的一致性和有效性。
g. 持续集成
- 自动化测试:将单元测试集成到持续集成 (CI) 流程中,确保每次代码提交都能自动运行测试。
- 如果你用的是maven和jdk版本过高,打war可能会出现错误,原因是war包打包插件和jdk版本不匹配:pom.xml 添加以下代码即可
4. 注意:打包(package)和安装(install)的区别是什么?
- 打包是将工程打成jar或war文件,保存在target目录下
- 安装是将当前工程所生成的jar或war文件,安装到本地仓库,会按照坐标保存到指定位置
- 坐标就按照坐标,到本地仓库,通过groupId,artifactId,version就能找到对应的jar包
可视化方式项目构建
构建插件,命令,生命周期命令之间关系
plugins和lifecycle的区别
- Maven Plugin(插件)
定义:Maven 插件是一组功能的集合,它们可以扩展 Maven 的能力,执行特定的任务或目标(goals)。插件是 Maven 构建过程中的重要组成部分,允许用户自定义构建过程。
功能:
- 目标(Goals):每个插件可以包含多个目标,目标是插件要执行的具体操作。例如,
maven-compiler-plugin
插件的目标可以是编译源代码。
- 配置:可以通过
pom.xml
文件中的<build>
标签配置插件的行为。
- 常用插件:常见的 Maven 插件包括
maven-compiler-plugin
(编译代码)、maven-surefire-plugin
(运行单元测试)、maven-jar-plugin
(打包 JAR 文件)等。
示例:
b. Maven Lifecycle(生命周期)
定义:Maven 生命周期是一系列按顺序执行的阶段,用于管理项目的构建过程。每个生命周期由多个阶段(phases)组成,这些阶段定义了项目的构建、测试、打包和部署等步骤。
功能:
- 生命周期阶段:每个阶段都是一个具体的构建步骤,例如
validate
(验证项目是否正确)、compile
(编译源代码)、test
(运行测试)、package
(打包项目)等。
- 默认生命周期:Maven 提供了三个内置的生命周期:
- 默认生命周期:用于构建和发布项目。
- 清理生命周期:用于清理项目的输出(例如删除目标目录)。
- 站点生命周期:用于生成项目的站点文档。
示例:执行
mvn package
命令时,Maven 会依次执行以下阶段:validate
compile
test
package
c. 区别总结
- 功能:插件是执行具体操作的工具,而生命周期是定义构建过程的顺序和阶段。
- 使用方式:插件可以在
pom.xml
中配置,而生命周期是 Maven 的核心概念之一,不需要配置。
- 执行:生命周期中每个阶段可以自动调用相关插件的目标。例如,在
package
阶段,Maven 会调用maven-jar-plugin
插件的jar
目标来打包项目.在命令行中执行的命令就是生命周期功能mvn clean package, 如果只点击插件的某个功能他就只会执行插件对应的功能(单点执行),不会执行前置流程(类似于流水线前置多点执行)
d. 总结
Maven 的插件和生命周期是相辅相成的。插件提供了实现具体任务的能力,而生命周期则组织了这些任务的执行顺序。理解这两者的区别对于有效地使用 Maven 进行项目管理和构建至关重要。
构建生命周期
- 我们发现一个情况!当我们执行package命令也会自动执行compile命令!
这种行为就是因为构建生命周期产生的!构建生命周期可以理解成是一组固定构建命令的有序集合,触发周期后的命令,会自动触发周期前的命令!!!
构建周期作用:会简化构建过程
- 例如:项目打包 mvn clean package即可。
主要两个构建生命周期:
清理周期:主要是对项目编译生成文件进行清理包含命令:clean
默认周期:定义了真正构件时所需要执行的所有步骤,它是生命周期中最核心的部分
- 插件、命令、周期三者关系(了解)
周期→包含若干命令→包含若干插件
使用周期命令构建,简化构建过程!
最终进行构建的是插件!
五 基于IDEA进行Maven依赖管理
依赖管理的概念
Maven 依赖管理是 Maven 软件中最重要的功能之一。Maven 的依赖管理能够帮助开发人员自动解决软件包依赖问题,使得开发人员能够轻松地将其他开发人员开发的模块或第三方框架集成到自己的应用程序或模块中,避免出现版本冲突和依赖缺失等问题。
我们通过定义 POM 文件,Maven 能够自动解析项目的依赖关系,并通过 Maven 仓库自动下载和管理依赖,从而避免了手动下载和管理依赖的繁琐工作和可能引发的版本冲突问题。
总之,Maven 的依赖管理是 Maven 软件的一个核心功能之一,使得软件包依赖的管理和使用更加智能和方便,简化了开发过程中的工作,并提高了软件质量和可维护性。
Maven工程核心信息配置和解读
文件位置pom.xml
- GAVP
- 依赖管理和依赖添加,dependencies标签(复数标签可以包含多个单数标签)
- 依赖版本统一提取和维护
依赖范围
通过设置坐标的依赖范围(scope),可以设置 对应jar包的作用范围(三种环境):编译环境(编译的时候是否需要)、测试环境(测试的时候是否需要)、运行环境(最终生成jar,war包里有没有,运行的时候需要不需要).
// scope的配置选项可选如下:
依赖范围 | 描述 |
compile | 编译依赖范围,scope 元素的缺省值。使用此依赖范围的 Maven 依赖,对于三种 classpath 均有效,即该 Maven 依赖在上述三种 classpath 均会被引入。例如,log4j 在编译、测试、运行过程都是必须的。 |
test | 测试依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath 有效。例如,Junit 依赖只有在测试阶段才需要。 |
provided | 已提供依赖范围。使用此依赖范围的 Maven 依赖,只对编译 classpath 和测试 classpath 有效。例如,servlet-api 依赖对于编译、测试阶段而言是需要的,但是运行阶段,由于外部容器已经提供,故不需要 Maven 重复引入该依赖。 |
runtime | 运行时依赖范围。使用此依赖范围的 Maven 依赖,只对测试 classpath、运行 classpath 有效。例如,JDBC 驱动实现依赖,其在编译时只需 JDK 提供的 JDBC 接口即可,只有测试、运行阶段才需要实现了 JDBC 接口的驱动。 |
system | 系统依赖范围,其效果与 provided 的依赖范围一致。其用于添加非 Maven 仓库的本地依赖,通过依赖元素 dependency 中的 systemPath 元素指定本地依赖的路径。鉴于使用其会导致项目的可移植性降低,一般不推荐使用。 |
import | 导入依赖范围,该依赖范围只能与 dependencyManagement 元素配合使用,其功能是将目标 pom.xml 文件中 dependencyManagement 的配置导入合并到当前 pom.xml 的 dependencyManagement 中。 |
Maven工程依赖下载失败错误解决(重点)
在使用 Maven 构建项目时,可能会发生依赖项下载错误的情况,主要原因有以下几种:
- 下载依赖时出现网络故障或仓库服务器宕机等原因,导致无法连接至 Maven 仓库,从而无法下载依赖。
- 依赖项的版本号或配置文件中的版本号错误,或者依赖项没有正确定义,导致 Maven 下载的依赖项与实际需要的不一致,从而引发错误。
- 本地 Maven 仓库或缓存被污染或损坏,导致 Maven 无法正确地使用现有的依赖项。(常见)
解决方案:
- 检查网络连接和 Maven 仓库服务器状态。
- 确保依赖项的版本号与项目对应的版本号匹配,并检查 POM 文件中的依赖项是否正确。
清除本地 Maven 仓库缓存(lastUpdated 文件),因为只要存在lastupdated缓存文件,刷新也不会重新下载。本地仓库中,根据依赖的gav属性依次向下查找文件夹,最终删除内部的文件,刷新重新下载即可!
例如: pom.xml依赖
文件:
或者可以将清除lastUpdated文件的操作写在一个脚本文件中,手动创建文件"clearLastUpdated.bat",名字任意,但是后缀必须是bat,将以下内容复制到文件中
Maven工程Build构建配置
- 项目构建是指将源代码、依赖库和资源文件等转换成可执行或可部署的应用程序的过程,在这个过程中包括编译源代码、链接依赖库、打包和部署等多个步骤。
- 默认情况下,构建不需要额外配置,都有对应的缺省配置。当然了,我们也可以在pom.xml定制一些配置,来修改默认构建的行为和产物!
例如:指定构建打包文件的名称,非默认名称;制定构建打包时,指定包含文件格式和排除文件;打包插件版本过低,配置更高版本插件
- 构建配置是在pom.xml / build标签中指定!
- 指定打包命名
- 指定打包文件
- 如果在java文件夹中添加java类,会自动打包编译到classes文件夹下!但是在java文件夹中添加xml文件,默认不会被打包!
- 默认情况下,按照maven工程结构放置的文件会默认被编译和打包!
- 除此之外、我们可以使用resources标签,指定要打包资源的文件夹要把哪些静态资源打包到 classes根目录下!
- 应用场景:mybatis中有时会将用于编写SQL语句的映射文件和mapper接口都写在src/main/java下的某个包中,此时映射文件就不会被打包,如何解决
- 配置依赖插件
- pom.xml 中的 JDK 版本:
- 这是项目级的配置,通常通过
<maven-compiler-plugin>
来设置,确保项目在编译时使用特定的 JDK 版本。例如: - 这保证了在编译时使用 Java 17 的语法和特性。
- settings.xml 中的配置:
settings.xml
是 Maven 的全局配置文件,通常用来配置代理、仓库、插件等。如果在其中设置了 JDK 版本,通常是为了指定 Maven 运行时的 JDK(比如通过JAVA_HOME
),但这个配置并不直接影响项目的编译。- 主要作用是影响 Maven 的行为,比如下载依赖和插件时所用的 JDK。
dependencies标签下引入开发需要的jar包!我们可以在build/plugins/plugin标签引入插件!
常用的插件:修改jdk版本、tomcat插件、mybatis分页插件、mybatis逆向工程插件等等!
补充说明一个问题:项目中pom中配置编译的jdk版本和Maven软件中的settings.xml中配置的编译jdk版本的配置区别?
在 Maven 项目中,
pom.xml
中的 build
部分配置的 JDK 版本和本地 Maven 的 settings.xml
中的配置有不同的作用:总的来说,
pom.xml
中的 JDK 版本主要影响项目的编译和构建,而 settings.xml
则影响 Maven 本身的运行环境。确保这两个配置一致可以避免潜在的编译和运行时问题。六 Maven依赖传递和依赖冲突
Maven依赖传递特性
- 概念:假如有Maven项目A,项目B依赖A,项目C依赖B。那么我们可以说 C依赖A。也就是说,依赖的关系为:C—>B—>A, 那么我们执行项目C时,会自动把B、A都下载导入到C项目的jar包文件夹中,这就是依赖的传递性。只要依赖了,不管是是不是自己直接依赖还是间接依赖都能够在上层使用.
- 作用:
- 简化依赖导入过程
- 确保依赖版本正确
- 传递的原则
- B 依赖 C 时使用 compile 范围:可以传递
- B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以。
- B 依赖 C 时,若配置了以下标签,则不能传递
在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围以及配置
- 依赖传递终止
- 非compile范围进行依赖传递
- 使用optional配置终止传递
- 依赖冲突(传递的依赖已经存在)
案例:导入jackson依赖
分析:jackson需要三个依赖
依赖传递关系:data-bind中,依赖其他两个依赖
最佳导入:直接可以导入data-bind,自动依赖传递需要的依赖
Maven依赖冲突特性
- 当直接引用或者间接引用出现了相同的jar包! 此时,一个项目就会出现相同的重复jar包,这就算作冲突!依赖冲突避免出现重复依赖,并且终止依赖传递!
- maven自动解决依赖冲突问题能力,会按照自己的原则,进行重复依赖选择。同时也提供了手动解决的冲突的方式,不过不推荐!
- 解决依赖冲突(如何选择重复依赖)方式:
- 自动选择原则
- 短路优先原则(第一原则)
- 依赖路径长度相同情况下,则“先声明优先”(第二原则)
- 手动排除
A—>B—>C—>D—>E—>X(version 0.0.1)
A—>F—>X(version 0.0.2)
则A依赖于X(version 0.0.2)。
A—>E—>X(version 0.0.1)
A—>F—>X(version 0.0.2)
在<depencies></depencies>中,先声明的,路径相同,会优先选择!
七 Maven工程继承和聚合关系
Maven工程继承关系
- 继承概念
Maven 继承是指在 Maven 的项目中,让一个项目从另一个项目中继承配置信息的机制。继承可以让我们在多个项目中共享同一配置信息,简化项目的管理和维护工作。
- 继承作用
- 对一个比较大型的项目进行了模块拆分。
- 一个 project 下面,创建了很多个 module。
- 每一个 module 都需要配置自己的依赖信息。
- 在每一个 module 中各自维护各自的依赖信息很容易发生出入,不易统一管理。
- 使用同一个框架内的不同 jar 包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
- 使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索。 通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力。
在父工程中统一管理项目中的依赖信息。
它的背景是:
它背后的需求是:
- 继承语法
- 父工程
- 子工程
创建或者添加子工程后
子工程和父工程的groupId是一样的
- 父工程依赖统一管理
- 如果在父工程中直接使用dependencies标签引入包,子工程会无条件继承这些依赖,与依赖范围无关。
- 父工程声明版本,使用dependencyManagement可以进行管理,不会被无条件引入
- 子工程引用版本
Maven工程聚合关系
- 聚合概念
Maven 聚合是指将多个项目组织到一个父级项目中,以便一起构建和管理的机制。聚合可以帮助我们更好地管理一组相关的子项目,同时简化它们的构建和部署过程。
- 聚合作用
- 管理多个子项目:通过聚合,可以将多个子项目组织在一起,方便管理和维护。
- 构建和发布一组相关的项目:通过聚合,可以在一个命令中构建和发布多个相关的项目,简化了部署和维护工作。
- 优化构建顺序:通过聚合,可以对多个项目进行顺序控制,避免出现构建依赖混乱导致构建失败的情况。
- 统一管理依赖项:通过聚合,可以在父项目中管理公共依赖项和插件,避免重复定义。
- 聚合语法:父项目中包含的子项目列表。
- 通过触发父工程构建命令、引发所有子模块构建!产生反应堆!
八 Maven私服
- 私服简介
Maven 私服是一种特殊的Maven远程仓库,它是架设在局域网内的仓库服务,用来代理位于外部的远程仓库(中央仓库、其他远程公共仓库)。
当然也并不是说私服只能建立在局域网,也有很多公司会直接把私服部署到公网,具体还是得看公司业务的性质是否是保密的等等,因为局域网的话只能在公司用,部署到公网的话员工在家里也可以办公使用。
- 建立了 Maven 私服后,当局域网内的用户需要某个构件时,会按照如下顺序进行请求和下载。
- 请求本地仓库,若本地仓库不存在所需构件,则跳转到第 2 步; 请求 Maven 私服,将所需构件下载到本地仓库,若私服中不存在所需构件,则跳转到第 3 步。 请求外部的远程仓库,将所需构件下载并缓存到 Maven 私服,若外部远程仓库不存在所需构件,则 Maven 直接报错。
- 此外,一些无法从外部仓库下载到的构件,也能从本地上传到私服供其他人使用。
- Maven私服的优势
- 节省外网带宽 消除对外部远程仓库的大量重复请求(会消耗很大量的带宽),降低外网带宽压力。
- 下载速度更快 Maven私服位于局域网内,从私服下载构建更快更稳定。
- 便于部署第三方构件 有些构件无法从任何一个远程仓库中获得(如:公司或组织内部的私有构件、Oracle的JDBC驱动等),建立私服之后,就可以将这些构件部署到私服中,供内部Maven项目使用。
- 提高项目的稳定性,增强对项目的控制 如果不建立私服,那么Maven项目的构件就高度依赖外部的远程仓库,若外部网络不稳定,则项目的构建过程也会变得不稳定。建立私服后,即使外部网络状况不佳甚至中断,只要私服中已经缓存了所需的构件,Maven也能够正常运行。私服软件(如:Nexus)提供了很多控制功能(如:权限管理、RELEASE/SNAPSHOT版本控制等),可以对仓库进行一些更加高级的控制。
- 降低中央仓库得负荷压力 由于私服会缓存中央仓库得构件,避免了很多对中央仓库的重复下载,降低了中央仓库的负荷。
- 常见的Maven私服产品
- Apache的Archiva
- JFrog的Artifactory
- Sonatype的Nexus([ˈneksəs])(当前最流行、使用最广泛)
- Nexus下载安装 // 复习省略了,一般不用自己搭建,下面配置的mirror地址一般填写的是公司的私服
- 通过nexus下载Jar包.
- 需要修改本地Maven核心配置文件settings.xml,设置新的本地仓库地址
- 把我们原来配置阿里云仓库地址的 mirror 标签改成下面这样:
- 将 jar 包部署到 Nexus
- Maven工程中配置:
- 引用别人部署的jar包
- Maven工程中的配置
九 案例分析
- 项目需求和结构分析
- 用户服务:负责处理用户相关的逻辑,例如用户信息的管理、用户注册、登录等。
- spring-context 6.0.6
- spring-core 6.0.6
- spring-beans 6.0.6
- common-service
- 订单服务:负责处理订单相关的逻辑,例如订单的创建、订单支付、退货、订单查看等。
- spring-context 6.0.6
- spring-core 6.0.6
- spring-beans 6.0.6
- spring-security 6.0.6
- common-service
- 通用模块:负责存储其他服务需要通用工具类,其他服务依赖此模块。
- commons-io 2.11.0
- junit 5.9.2
需求案例:搭建一个电商平台项目,该平台包括用户服务、订单服务、通用工具模块等。
项目架构:
- 配置实现
- 默认版本
- 父工程
micro-shop
的版本:1.0-SNAPSHOT(在父pom.xml
中定义) - 子模块的默认版本:
common-service
:1.0-SNAPSHOT(继承自父工程)user-service
:1.0-SNAPSHOT(继承自父工程)order-service
:1.0-SNAPSHOT(继承自父工程)- ${project.version}使用
${project.version}
:这个变量指代当前模块(子项目)的版本。在子模块中,它的值就是子模块的<version>
元素定义的值。- 无须在
properties
中定义:因为这个变量是内置的,Maven会自动处理并解析它,因此你不需要在properties
中显式定义。 - 统一管理和独立版本管理
- 统一版本:适用于功能相近且频繁发布的模块,便于管理和协调版本。
- 独立版本:适用于模块功能差异大,更新频率不同的情况,允许每个模块独立演进。
common-service
: 1.0.0user-service
: 1.0.0order-service
: 1.0.0
父工程
创建工程
pom配置(可选操作:删除src目录)
通用模块 (common-service)
创建工程
pom.xml配置:
用户模块 (user-service)
创建工程
pom.xml配置:
依赖传递结果:
订单模块 (order-service)
创建工程,并使用插件转为web工程:
pom.xml配置:
其他说明
如果在Maven的
pom.xml
中没有明确指定子模块的版本,子模块将默认继承父模块的版本号。在你的例子中:总结
如果你没有在子模块的
pom.xml
中单独定义版本,所有子模块的版本将默认是父工程的版本,即 1.0-SNAPSHOT。这对于保持一致性和简化版本管理非常有用。在Maven中,
${project.version}
是一个特殊的变量,它代表当前模块的版本号。当你在一个子模块的 pom.xml
中使用 ${project.version}
时,它会自动解析为该模块的版本号。具体解释
示例
如果你在
order-service/pom.xml
中使用了:这表示
order-service
依赖于 common-service
,并且其版本将自动使用 order-service
的版本。例如,如果 order-service
的版本是 1.0.0
,那么 ${project.version}
将被解析为 1.0.0
。总结
使用
${project.version}
是一种便捷的方式,可以确保依赖的版本与当前模块的版本保持一致。这种做法适用于需要引用当前模块自身的版本的场景。要为
user-service
、common-service
和 order-service
定义各自的版本,可以采用以下几种方式:a. 统一版本管理
如果你希望所有子模块保持相同的版本,可以在父工程的
pom.xml
中定义一个统一的版本号。所有子模块都继承这个版本号。b. 独立版本管理
如果每个子模块有不同的版本号,你可以在各自的
pom.xml
中单独指定版本。以下是一个示例:父工程
micro-shop/pom.xml
通用模块
common-service/pom.xml
用户服务
user-service/pom.xml
订单服务
order-service/pom.xml
版本管理策略
版本号示例
- 多环境使用不同配置(profiles)
Maven允许你定义多个构建配置(profiles),你可以为不同的环境创建不同的profile。这些profile可以包含特定的依赖、插件和属性。
在
pom.xml
中定义 Profiles十 其他学习资料
‣
- 作者:coderma4k
- 链接:https://coderma4k.com//article/129bd2a3-ceeb-80cc-ae66-f6c350c850d9
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。