Maven工具详情
简介
Maven是一个依赖管理工具和构建工具,主要用途式用来管理项目和下载项目所需的jar包
Maven也可以对jar包进行共享,在企业开发中公司会搭建maven的私服(nexus)用来共享公司内部开发的jar包
使用maven使用坐标来进行导入jar包,坐标是在pom文件中的 dependencys标签中书写的,通过配置maven的坐标就可以找到相对应的jar包
首先会在本地仓库去寻找,如果本地仓库没有相对应的jar包,那么就去远程仓库(镜像仓库 | 中央仓库 | 私服)中去进行下载到本地仓库,然后使用
<dependency>
<groupId>组织</groupId>
<artifactId>模块</artifactId>
<version>版本号</version>
</dependency>maven仓库

远程仓库有三种,中央仓库是maven的官方仓库,如果maven的配置文件不配置的话就会在中央仓库进行下载相对应的jar包;私服是一种特殊的远程仓库,其内容是来自于其他的远程仓库,一般架设在局域网内,提供给一个组织的人员使用;第三方公共库(镜像仓库)是中央仓库的镜像,因为中央仓库的服务器不在国内,所以下载会很慢,所以在国内搭建一个镜像会让下载更舒服,如:阿里云
jar包寻找依赖的流程
首先会根据依赖去本地仓库中寻找,如果存在直接返回,没有则去远程仓库
在远程仓库中找到相对应的jar包时会把jar包下载到本地仓库,然后使用
GAVP
Maven 中的 GAVP 是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写,其中前三个是必要的,而 Packaging 属性为可选项
这四个属性主要为每个项目在maven仓库总做一个标识,方便maven软件对项目进行管理和互相引用
GroupID
格式:com.{公司/BU }.业务线.[子业务线],最多 4 级
说明:
例如:alibaba/taobao/tmall/aliexpress 等 BU 一级;子业务线可选
正例:com.taobao.tddl 或 com.alibaba.sourcing.multilang com.atguigu.java
ArtifactID
格式:产品线名-模块名。语义不重复不遗漏,先到仓库中心去查证一下
正例:tc-client / uic-api / tair-tool / bookstore
Version
版本号格式推荐:主版本号.次版本号.修订号 1.0.0
- 主版本号:当做了不兼容的 API 修改,或者增加了能改变产品方向的新功能
- 次版本号:当做了向下兼容的功能性新增(新增类、接口等)
- 修订号:修复 bug,没有修改方法签名的功能加强,保持 API 兼容性
例如: 初始→1.0.0 修改bug → 1.0.1 功能调整 → 1.1.1等
Packaging
指示将项目打包为什么类型的文件,idea根据packaging值,识别maven项目类型
packaging 属性为 jar(默认值),代表普通的Java工程,打包以后是.jar结尾的文件
packaging 属性为 war,代表Java的web工程,打包以后.war结尾的文件
packaging 属性为 pom,代表不会打包,用来做继承的父工程
生命周期
Maven的生命周期包括:清理、编译、测试、打包、安装、部署
对应命令如下:
| 功能 | 命令 | 作用 |
|---|---|---|
| 清理 | mvn clean | 将会删除 target 目录及内容 |
| 编译 | mvn compile | 将java文件编译为 class 文件输出到 target 目录下 |
| 测试 | mvn test | 执行单元测试类 |
| 打包 | mvn package | 把项目打包到项目的target目录 |
| 安装 | mvn install | 包含package,且将项目打包安装到本地仓库 |
| 部署 | mvn deploy | 包含install,且将项目上传到远程仓库 |
如果想要一次性执行多个命令,是可以命令跟命令的,如:mvn clean compile test
如果手动进行输入指令,那么需要在与pom文件同级别的路径下执行
测试(mvn test)
在maven中对于测试类以及测试方法是有一定命名要求的
对于测试类:命名是要以Test开头或者结尾的(一般建议结尾)
对于测试方法:一般要以test为开头后面跟上要测试的方法名
只有命名达到要求才能被test命令正常测试
测试报告
执行测试命令之后,会生在target文件夹中生成一个surefire-reports文件夹,这里面存放着测试报告
打war包出错
在web工程中,打war包出错,war包的打包插件与jdk的版本不匹配,需要在pom文件中加入如下代码,这是一个打war包的插件
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>依赖管理概念:maven重要的功能之一,能够帮助开发人员自动解决软件包依赖问题,避免出现版本冲突和依赖缺失等问题
依赖范围
在dependency标签中的scope标签内书写依赖范围
依赖范围(Dependency Scope)指定了编译、测试和运行时类路径中依赖项的作用范围
以下是 Maven 中常用的依赖范围
| 范围 | 说明 |
|---|---|
| compile | 默认范围,适用于编译、测试和运行时,该依赖项将在所有三个阶段(编译、测试、运行)中可用 |
| provided | 适用于编译和测试,但在运行时应由 JDK 或容器提供,例如,Servlet API 就是一个常见的 provided 依赖 |
| runtime | 适用于运行时和测试,但不在编译时需要,这些依赖项在运行时可用,但不会包含在编译类路径中 |
| test | 适用于测试时,不会在编译或运行时包含在类路径中,这些依赖项仅在测试代码编译和执行时可用 |
| system | 与 provided 类似,但需要显式提供路径到 JAR 文件,不推荐使用此范围,因为它会绕过 Maven 仓库的管理 |
| import | 仅用于 部分,表示导入依赖的版本范围,但不实际参与构建 |
| compile-only (Maven 3.3.1+) | 适用于编译时,但不参与测试和运行时,这种范围在编译类路径中有效,但在测试和运行时不可用 |
| test-compile (Maven 3.3.1+) | 适用于测试编译时,不参与运行时,这种范围在测试编译类路径中有效,但在运行时不可用 |
| provided-compile (Maven 3.3.1+) | 适用于编译和测试,但在运行时应由 JDK 或容器提供,该范围在编译和测试类路径中有效,但在运行时不可用 |
依赖版本
在properties标签内除了有设置字符编码和jdk版本的属性也可以管理依赖的版本,例:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--依赖版本-->
<junit.jupiter.version>5.9.2</junit.jupiter.version>
<lombok.version>1.18.30</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>依赖传递
依赖传递指的是当一个模块或库 A 依赖于另一个模块或库 B,而 B 又依赖于模块或库 C,那么 A 会间接依赖于 C,这种依赖传递结构可以形成一个依赖树
作用
- 减少重复依赖:当多个项目依赖同一个库时,Maven 可以自动下载并且只下载一次该库,这样可以减少项目的构建时间和磁盘空间
- 自动管理依赖: Maven 可以自动管理依赖项,使用依赖传递,简化了依赖项的管理,使项目构建更加可靠和一致
- 确保依赖版本正确性:通过依赖传递的依赖,之间都不会存在版本兼容性问题,确实依赖的版本正确性
传递原则
在A依赖B,B依赖C的前提下,C是否能够传递到A,取决于B依赖C时使用的依赖泛起以及配置
- compile范围:可以传递
- 其他范围:不可以传递
- 在
dependency中设置optional为true,表示不传递依赖
传递终止
- 非compile范围进行依赖传递
- 使用optional配置终止传递
- 依赖冲突(传递依赖已经存在)
依赖冲突及解决方法
当直接引用或者间接引用出现了相同的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)
在中,先声明的,路径相同,会优先选择
手动
手动排除依赖
<dependencies>
<!--导入的依赖-->
<dependency>
<groupId>xxx.xxx</groupId>
<artifactId>xxx</artifactId>
<version>x.x.x</version>
<scope>xxx</scope>
<!--需要排除的依赖信息-->
<exclusions>
<exclusion>
<groupId>sss.sss</groupId>
<artifactId>sss</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>这样就会把xxx工程中的sss依赖排除在外
Build构建配置
项目构建是指将源代码、依赖库和资源文件等转换成可执行或可部署的应用程序的过程,在这个过程中包括编译源代码、链接依赖库、打包和部署等多个步骤
主动触发场景:
- 重新编译:编译不充分,部分文件没有被编译!
- 打包:独立部署到外部服务器软件,打包部署
- 部署本地或者私服仓库:maven工程加入到本地或者私服仓库,供其他工程使用
指定打包命名
<!-- 默认打包名称:artifactId-version.packaging -->
<build>
<finalName>xxx.xxx</finalName>
</build>设置自定义打包时一定要加上应有的后缀
指定打包文件
在maven项目中src/main目录下有两个文件,根据maven规则,java文件夹中只能放.java为后缀的文件,在编译时maven会把java文件夹中的java文件打包,不是java文件不会打包,resources文件夹中存放的是配置文件以及其他文件
在某些特殊的场景下,java文件夹中会存放一些不是java后缀的文件,但是想要一起打包到包中,可以在build标签中进行设置
<build>
<!-- 设置要打包的资源位置 -->
<resources>
<resource>
<!-- 设置资源所在目录 -->
<directory>src/main/java</directory>
<includes>
<!-- 设置包含资源类型-->
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>常用插件
插件配置写在build > plugins中
java编译插件,配置jdk的编译版本
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>tomcat插件
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<uriEncoding>UTF-8</uriEncoding>
<path>/</path>
<server>tomcat7</server>
</configuration>
</plugin>工程继承关系
Maven 继承是指在 Maven 的项目中,让一个项目从另一个项目中继承配置信息的机制。继承可以让我们在多个项目中共享同一配置信息,简化项目的管理和维护工作
作用:在父工程中统一管理项目中的依赖信息
背景
- 对一个比较大的项目进行模块拆分
- 一个project下面创建了多个module
- 每一个module都需要配置自己的依赖信息
需求
- 多个模块要使用同一个框架,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一管理
- 使用框架时所需要的 jar 包组合(或者说依赖信息组合)需要经过长期摸索和反复调试,最终确定一个可用组合。这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索
- 通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力
继承语法
父项目pom
...
<groupId>xxx.xxx</groupId>
<artifactId>xxx</artifactId>
<version>x.x.x</version>
<!-- 打包方式 -->
<packaging>pom</packaging>
<!-- 要聚合的子工程路径 -->
<modules>
<module>test_1</module>
</modules>
...子模块pom
...
<!-- 父工程坐标 -->
<parent>
<groupId>xxx.xxx</groupId>
<artifactId>xxx.xxx</artifactId>
<version>xxx.xxx</version>
</parent>
<!-- 子模块名 -->
<artifactId>test_1</artifactId>
...父工程的打包方式要设置成pom,因为父工程不参与打包没有代码只进行依赖管理或配置信息的管理
子工程中的artifactId与version要与父工程的保持一致,所以省略了groupId和version
父子工程依赖
如果直接在父工程中导入依赖,那么被导入的依赖会异界继承给所有的子工程
父工程依赖统一管理
父工程定义(pom)
<!--依赖声明-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>子工程引用(pom)
<dependencies>
<!--引用定义好的依赖-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
</dependencies>dependencyManagement与dependencies的区别就是直接在dependencies中写入的插件会被直接继承,dependencyManagement中写入需要子工程手动的进行引入
工程的聚合关系
概念:Maven 聚合是指将多个项目组织到一个父级项目中,通过触发父工程的构建,统一按顺序触发子工程构建的过程!
作用
- 统一管理子项目构建:通过聚合,可以将多个子项目组织在一起,方便管理和维护
- 优化构建顺序:通过聚合,可以对多个项目进行顺序控制,避免出现构建依赖混乱导致构建失败的情况
语法
在父工程的pom文件中有这样一组标签
<modules>
<!-- 要聚合的子工程路径 -->
<module>test_1</module>
<module>test_2</module>
<module>test_3</module>
</modules>在IDEA中,手动创建模块之后会自动在父工程的pom文件中进行创建或者添加该标签
