1、Maven的介绍和作用
maven是什么?为什么服务?主要功能是什么?
Maven是一个为java项目构建管理和依赖管理的工具(软件)。
既然是一个软件,我们主要关注点应该在于 它如何安装,配置以及基本使用。
简单了解依赖管理和项目构建。
依赖管理:
我们使用java进行开发时,可能需要大量的第三方jar包,比如jdk等等。如果使用了Maven,只需要简单编写一个配置文件,他可以帮我们安装第三方包,以及帮助我们安装第三方包所依赖的包,同时还会避免版本冲突的问题。
项目构建:
1、使用maven 命令简单方便
2、不同的软件,项目构建不同,使用eclipse和idea就不同,如果在idea上构建的项目,在idea上由于项目构建方式不同,可能出现错误,此时我们就可以使用maven来统一进行项目构建,来打包等。可以使用idea+maven或者eclipse+maven。
2、基于IDEA的Maven工程创建
这里使用的是2021.3.2 版本
2.1 GAVP属性
Maven工程相对之前的工程,多出一组gavp属性,gav需要我们在创建项目的时指定,p有默认值,后期Maven 中的 GAVP 是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写,其中前三个是必要的,而 Packaging 属性为可选项。
这四个属性主要为每个项目在maven仓库总做一个标识,类似人的《姓-名》。有了具体标识,方便maven软件对项目进行管理和互相引用!通过配置文件修改。既然要填写的属性,我们先行了解下这组属性的含义!
GAV遵循以下规则:
1) **GroupID 格式**:com.{公司/BU }.业务线.[子业务线],最多 4 级。
说明:{公司/BU} 例如:alibaba/taobao/tmall/aliexpress 等 BU 一级;子业务线可选。
正例:com.taobao.tddl 或 com.alibaba.sourcing.multilang com.atguigu.java
2) **ArtifactID 格式**:产品线名-模块名。语义不重复不遗漏,先到仓库中心去查证一下。
正例:tc-client / uic-api / tair-tool / bookstore
3) **Version版本号格式推荐**:主版本号.次版本号.修订号 1.0.0(不同公司规则可能不同)
1) 主版本号:当做了不兼容的 API 修改,或者增加了能改变产品方向的新功能。
2) 次版本号:当做了向下兼容的功能性新增(新增类、接口等)。
3) 修订号:修复 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,代表不会打包,用来做继承的父工程。
第一个红线框的项目名:用于在本电脑内查找java文件。
第二个红线框的ArticleID 用于在MEAVN中查找java文件。 名字可以相同。
2.2、创建Maven JAVAEE项目
a.安装插件
b.创建一个javasemaven工程
c.右键,使用插件快速补全web项目
javaeemaven工程
2.3 Maven工程项目结构说明
Maven 是一个强大的构建工具,它提供一种标准化的项目结构,可以帮助开发者更容易地管理项目的依赖、构建、测试和发布等任务。以下是 Maven Web 程序的文件结构及每个文件的作用:
|-- pom.xml # Maven 项目管理文件
|-- src
|-- main # 项目主要代码
| |-- java # Java 源代码目录
| | `-- com/example/myapp # 开发者代码主目录
| | |-- controller # 存放 Controller 层代码的目录
| | |-- service # 存放 Service 层代码的目录
| | |-- dao # 存放 DAO 层代码的目录
| | `-- model # 存放数据模型的目录
| |-- resources # 资源目录,存放配置文件、静态资源等
| | |-- log4j.properties # 日志配置文件
| | |-- spring-mybatis.xml # Spring Mybatis 配置文件
| | `-- static # 存放静态资源的目录
| | |-- css # 存放 CSS 文件的目录
| | |-- js # 存放 JavaScript 文件的目录
| | `-- images # 存放图片资源的目录
| `-- webapp # 存放 WEB 相关配置和资源
| |-- WEB-INF # 存放 WEB 应用配置文件
| | |-- web.xml # Web 应用的部署描述文件
| | `-- classes # 存放编译后的 class 文件
| `-- index.html # Web 应用入口页面
`-- test # 项目测试代码
|-- java # 单元测试目录
`-- resources # 测试资源目录
3、Maven核心功能 依赖管理
Maven 依赖管理是 Maven 软件中最重要的功能之一。Maven 的依赖管理能够帮助开发人员自动解决软件包依赖问题,使得开发人员能够轻松地将其他开发人员开发的模块或第三方框架集成到自己的应用程序或模块中,避免出现版本冲突和依赖缺失等问题。
我们通过定义 POM 文件,Maven 能够自动解析项目的依赖关系,并通过 Maven 仓库自动下载和管理依赖,从而避免了手动下载和管理依赖的繁琐工作和可能引发的版本冲突问题。
3.1 如何查找 依赖项的gav属性
1、 去官网中查找
但是比较慢
mvnrepository.com
2、在idea中下载插件 maven-search
找对应名称,复制到pom中即可
Maven项目信息配置和提取
<!-- 模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group -->
<groupId>com.companyname.project-group</groupId>
<!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
<artifactId>project</artifactId>
<!-- 版本号 -->
<version>1.0.0</version>
<!--打包方式
默认:jar
jar指的是普通的java项目打包方式! 项目打成jar包!
war指的是web项目打包方式!项目打成war包!
pom不会讲项目打包!这个项目作为父工程,被其他工程聚合或者继承!后面会讲解两个概念
-->
<packaging>jar/pom/war</packaging>
依赖管理和添加
<!--
通过编写依赖jar包的gav必要属性,引入第三方依赖!
scope属性是可选的,可以指定依赖生效范围!
依赖信息查询方式:
1. maven仓库信息官网 https://mvnrepository.com/
2. mavensearch插件搜索
-->
<dependencies>
<!-- 引入具体的依赖包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<!--
生效范围
- compile :main目录 test目录 打包打包 [默认]
- provided:main目录 test目录 Servlet
- runtime: 打包运行 MySQL
- test: test目录 junit
-->
<scope>runtime</scope>
</dependency>
</dependencies>
生效范围scope是一个锦上添花的东西,如果不会使用,就默认值就可以
版本依赖提取和维护
<!--声明版本-->
<properties>
<!--命名随便,内部制定版本号即可!-->
<junit.version>4.11</junit.version>
<!-- 也可以通过 maven规定的固定的key,配置maven的参数!如下配置编码格式!-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--引用properties声明版本 -->
<version>${junit.version}</version>
</dependency>
</dependencies>
将版本号设置为以恶个全局变量,以便之后使用。在之后版本配置中,可以通过${xxx}访问。
3.2 依赖传递与冲突
3.2.1依赖传递
比如 A依赖于B,B依赖于C,那么A间接依赖于C,在引入A的同时,会自动引入B和C。
依赖传递的作用:
1. 减少重复引入,当多个项目依赖同一个库时,Maven 可以自动下载并且只下载一次该库。这样可以减少项目的构建时间和磁盘空间。
2. 自动管理依赖: Maven 可以自动管理依赖项,使用依赖传递,简化了依赖项的管理,使项目构建更加可靠和一致。
3. 确保依赖版本正确性:通过依赖传递的依赖,之间都不会存在版本兼容性问题,确实依赖的版本正确性!
依赖传递演示:
项目中,需要导入jackson相关的依赖,通过之前导入经验,jackson需要导入三个依赖,分别为:
通过查看网站介绍的依赖传递特性:data-bind中,依赖其他两个依赖
只看Compile Dependencies 中的依赖项。
最佳导入:直接可以导入data-bind,自动依赖传递需要的依赖
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
我们可以看到:只导入了一个,其它两个会自动导入,且导入的版本正确。
3.2.2 依赖冲突
同一个包可能会引用不同的jar包。
当直接引用或者间接引用出现了相同的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>中,先声明的,路径相同,会优先选择!
如果在配置中先配置了E,就会导入X 0.0.1版本,如果先配置了F,就会导入0.0.2版本.
下面思考一个案例:会导入那些jar包呢?
前提:
A 1.1 -> B 1.1 -> C 1.1
F 2.2 -> B 2.2
pom声明:
F 2.2
A 1.1
B 2.2
答案:会导入 A1.1 F2.2 B2.2 不会引入C1.1 因为B1.1 引用发生了冲突,后续的引用将全部终止。
3.3 依赖导入失败场景和解决方法
(1)本地库或中央仓库出错。下载依赖jar包,首先先搜索本地库,再去搜索中央仓库。
解决办法:检查网络连接和 Maven 仓库服务器状态。
(2)依赖项的版本号或配置文件中的版本号错误,或者依赖项没有正确定义,导致 Maven 下载的依赖项与实际需要的不一致,从而引发错误。
解决办法:确保依赖项的版本号与项目对应的版本号匹配,并检查 POM 文件中的依赖项是否正确。
(3)本地 Maven 仓库或缓存被污染或损坏,导致 Maven 无法正确地使用现有的依赖项,并且也无法重新下载!
解决办法:清除本地 Maven 仓库缓存(lastUpdated 文件),因为只要存在lastupdated缓存文件,刷新也不会重新下载。本地仓库中,根据依赖的gav属性依次向下查找文件夹,最终删除内部的文件,刷新重新下载即可
4、Maven 扩展构建管理与插件配置
4.1 构建的概念:
项目构建是指将源代码、依赖库和资源文件等转换成可执行或可部署的应用程序的过程,在这个过程中包括编译源代码、链接依赖库、打包和部署等多个步骤。
主动触发场景:
- 重新编译 : 编译不充分, 部分文件没有被编译!
- 打包 : 独立部署到外部服务器软件,打包部署
- 部署本地或者私服仓库 : maven工程加入到本地或者私服仓库,供其他工程使用
4.2 命令方式构建:
语法: mvn 构建命令 构建命令....
4.3 可视化方式构建:
4.4 构建命令周期:
构建生命周期可以理解成是一组固定构建命令的有序集合,触发周期后的命令,会自动触发周期前的命令!也是一种简化构建的思路!
Maven有3个周期
- 清理周期:主要是对项目编译生成文件进行清理
包含命令:clean
- 默认周期:定义了真正构件时所需要执行的所有步骤,它是生命周期中最核心的部分
包含命令:compile - test - package - install / deploy
- 报告周期
包含命令:site
打包: mvn clean package 本地仓库: mvn clean install
使用最佳方案:
打包: mvn clean package
重新编译: mvn clean compile
本地部署: mvn clean install
4.5 周期,命令和插件:
周期→包含若干命令→包含若干插件!
使用周期命令构建,简化构建过程!
最终进行构建的是插件!
周期命令包含多个命令,一条命令可包含若干插件。
4.6 注意:
如果我们打包war工程,可能会出错。
因为Maven自带的war插件是 2.2
此时我们需要自定义插件,在pom配置项目中。
<build>
<!-- jdk17 和 war包版本插件不匹配 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
</plugins>
</build>
成功更新war包version
再次打包 mvn clean package
5、Maven工程继承与聚合特性
5.1 继承特性
5.1.1 继承概念
Maven 继承是指在 Maven 的项目中,让一个项目从另一个项目中继承配置信息的机制。继承可以让我们在多个项目中共享同一配置信息,简化项目的管理和维护工作。
5.1.2 继承作用
作用:在父工程中统一管理项目中的依赖信息,进行统一版本管理!
5.1.3 实例:
背景: 一个较大的工程,进行模块拆分。一个project下有许多module,一个module下需要有自己的依赖。 父工程:maven-parent 子工程:cky-buy,cky-user
需求:
对于不同的module,需要使用同一个框架,所以说框架所依赖的版本应该是同一个。
所以,此时,我们就需要一个父工程,该父工程并不会被打包,也不应该在父工程中编写代码,父工程pom文件中,package 为pom,且src文件夹被删除。
父工程是为了进行依赖的版本控制管理,如果在父工程的<dependencies>中写依赖管理,则父工程项目下的所有子工程,都会导入该依赖管理,但是其实一些子工程并不需要该依赖,所以我们需要的是在父工程的<dependencyManagement>下导入依赖的gav属性,只需要在子工程下导入依赖的ga属性即可,这样子,就不会导入该依赖项,而只是为了给子工程享用一个依赖的版本控制信息。
如:父工程:
子工程:子工程会继承父工程的版本信息。
结果:
可以看出,父工程并没有导入依赖,子工程导入了各自所需要的依赖,并且是按照夫工程的版本。
5.2 聚合特性
5.2.1 聚合和继承的区别与联系
集合和聚成一般是同时存在的。
聚合一般而言是在项目构建中使用,使用了父工程的clean,就会触发子工程的clean。
而继承一般而言是在项目依赖中,父工程的pom规定了依赖的gav属性,只需要在子工程中规定依赖的ga属性即可。版本信息是继承父工程的。
聚合是在父工程的pom中的modules中
而继承是在子工程pom的parent中
案例:
触发父工程的clean
则显示:
6、maven核心掌握点
版本提取:即我们在pom配置中的properties属性中标明某个依赖的版本信息,在依赖版本信息中使用${xxx}来提取版本号,这样子可以直接修改properties中的版本信息即可,而不用挨着依赖版本进行修改
如果要依赖于自己的maven项目,则该被依赖的maven首先需要部署到本地库或私服库(mvn install),之后按照gav同样的方法在pom文件中进行依赖书写。和依赖其他的maven项目相同。