1. Maven简介和安装
1.1. Maven是一个依赖管理工具
- 问题:
- jar包的规模
随着使用框架越来越多,或框架的封装程度越来越高,项目中使用的jar包也越来越多。项目中,一个模块里用到上百个jar包是非常正常的 - jar包的来源
- jar包所属技术官网
- 第三方下载网站
- 使用maven后,依赖对应的jar包能够自动下载,方便、快捷、规范
- jar包的导入问题
在web工程中,jar包必须存放在指定位置
使用maven之后,通过配置依赖的坐标,查找本地仓库中相应jar包,若本地仓库没有,统一从镜像网站或中央仓库中下载 - jar包之间的依赖
框架中使用的jar包,不仅数量庞大,而且彼此之间存在错综复杂的依赖关系,而且jar包之间可能产生冲突;使用maven几乎不需要管理这些关系,只需要调整极个别的地方,极大减轻了我们的工作量。
- jar包的规模
1.2. Maven介绍
Maven是一款为Java项目管理构建、依赖管理的工具,使用maven可以自动化构建、测试、打包和发布项目,大大提高了开发效率和质量
Maven的工作原理模型图
1.3. 安装和配置
https://maven.apache.org/docs/history.html
各个工具选用版本:
工具 | 版本 |
---|---|
Maven | 3.8.8 |
JDK | 17 |
Tomcat | 10 |
1.3.1. Maven功能配置
需要修改maven/conf/settings.xml配置文件,修改maven的一些默认配置。我们主要修改的配置:
- 依赖本地缓存位置(本地仓库位置)
<!-- conf/settings.xml -->
<localRepository>D:\maven-repository</localRepository>
- maven下载镜像
<!--配置国内阿里镜像-->
<!--在mirrors节点(标签)下添加中央仓库镜像-->
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
- maven选用编译项目的jdk版本
<!--在profiles节点(标签)下添加jdk编译版本-->
<profile>
<id>jdk-17</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>17</jdk>
</activation>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
</properties>
</profile>
1.4. 基于IDEA创建Maven工程
Maven工程相对之前的项目,多出一组gavp属性: GroupId、ArtifactId、Version、Packaging,其中前三个是必要的,Packaging 属性为可选项
-
Packaging定义规则:指示将项目打包为什么类型的文件,idea根据packaging值,识别maven项目类型
- jar(默认值):普通的Java工程,打包以后是.jar结尾的文件。
- war:代表Java的web工程,打包以后.war结尾的文件。
- pom:不会打包,用来做继承的父工程。
1.4.1. Maven工程项目结构说明
|-- 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 # 测试资源目录
1.5. Maven构建项目
- 命令方式构建
命令 | 描述 |
---|---|
mvn compile | 编译项目,生成target文件 |
mvn package | 打包项目,生成jar或war文件 |
mvn clean | 清理编译或打包后的项目结构 |
mvn install | 打包后上传到maven本地仓库 |
mvn deploy | 只打包,上传到maven私服仓库 |
mvn site | 生成站点 |
mvn test | 执行测试源码 |
如果war包打包插件和jdk版本不匹配:pom.xml 添加以下代码即可
<build>
<!-- jdk17 和 war包版本插件不匹配 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
</plugins>
</build>
- idea可视化方式构建
2. Maven依赖管理
通过定义POM文件,Maven能够自动解析项目的依赖关系,并通过Maven仓库自动下载和管理依赖
2.1. 核心信息配置(GAVP)
<!-- 模型版本 -->
<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-->
<packaging>jar/pom/war</packaging>
2.2. 依赖管理配置
- 依赖管理和添加
<!--
通过编写依赖jar包的gav必要属性,引入第三方依赖!
scope属性是可选的,可以指定依赖生效范围!
依赖信息查询方式:
1. maven仓库信息官网 https://mvnrepository.com/
2. mavensearch插件搜索
-->
<dependencies>
<!-- 引入具体的依赖包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<!-- 依赖范围 -->
<scope>runtime</scope>
</dependency>
</dependencies>
- 依赖版本统一提取和维护
<!--声明版本-->
<properties>
<!--命名随便,内部制定版本号即可!-->
<junit.version>4.12</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>
2.3. 依赖范围
依赖范围 | 描述 |
---|---|
compile | 编译依赖范围。对于三种 classpath 均有效。例如,log4j 在编译、测试、运行过程都是必须的。 |
test | 测试依赖范围。只对测试 classpath 有效。例如,Junit 依赖只有在测试阶段才需要。 |
provided | 已提供依赖范围。只对编译 classpath 和测试 classpath 有效。例如,servlet-api 依赖对于编译、测试阶段而言是需要的,但是运行阶段,由于外部容器已经提供,故不需要 Maven 重复引入该依赖。 |
runtime | 运行时依赖范围。只对测试 classpath、运行 classpath 有效。例如,JDBC 驱动实现依赖,其在编译时只需 JDK 提供的 JDBC 接口即可,只有测试、运行阶段才需要实现了 JDBC 接口的驱动。 |
2.4. Build构建配置
默认情况下,构建不需要额外配置。也可以在pom.xml定制一些配置,来修改默认构建的行为和产物
- 指定打包命名
<!-- 默认的打包名称:artifactid+verson.打包方式 -->
<build>
<finalName>定义打包名称</finalName>
</build>
- 指定打包文件
应用场景:mybatis中有时会将用于编写SQL语句的映射文件和mapper接口都写在src/main/java下的某个包中,此时映射文件就不会被打包
<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>
<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>8090</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
3. Maven依赖传递和依赖冲突
3.1. Maven依赖传递特性
依赖的传递性:假如有Maven项目A、B、C,B依赖A,C依赖B。那么我们可以说 C依赖A。依赖关系为:C—>B—>A, 执行项目C时,会自动把B、A都下载导入到C项目的jar包文件夹中,这就是依赖的传递性
- 传递的原则
- B 依赖 C 时使用 compile 范围:可以传递
- B 依赖 C 时使用 test 或 provided 范围:不能传递。
- B 依赖 C 时,若配置了以下标签,则不能传递
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
<optional>true</optional>
</dependency>
3.2. Maven依赖冲突特性
当直接或间接引用出现相同的jar包,一个项目就会出现相同的重复jar包,就是依赖冲突。依赖冲突避免出现重复依赖,并且终止依赖传递。
- 解决依赖冲突的方式
- 自动选择原则
- 短路优先原则(第一原则)
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>中,先声明的,路径相同,会优先选择
- 手动排除
<dependency>
<groupId>com.wyb.maven</groupId>
<artifactId>pro01-maven-java</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
<!-- 使用excludes标签配置依赖的排除 -->
<exclusions>
<!-- 在exclude标签中配置一个具体的排除 -->
<exclusion>
<!-- 指定要排除的依赖的坐标(不需要写version) -->
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
4. Maven工程继承和聚合关系
4.1. Maven工程继承关系
- 继承:在 Maven 的项目中,让一个项目从另一个项目中继承配置信息的机制。继承可以在多个项目中共享同一配置信息,简化项目的管理和维护工作。
- 继承作用:在父工程中统一管理项目中的依赖信息。
- 背景
- 对一个比较大型的项目进行模块拆分。
- 一个 project 下面,创建了很多个 module。
- 每一个 module 都需要配置自己的依赖信息。
- 背景
4.1.1. 继承语法
- 父工程
<groupId>com.wyb.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>
- 子工程
<!-- 使用parent标签指定当前工程的父工程 -->
<parent>
<!-- 父工程的坐标 -->
<groupId>com.wyb.maven</groupId>
<artifactId>pro03-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 子工程的坐标 -->
<!-- 如果子工程坐标中的groupId和version与父工程一致,那么可以省略 -->
<!-- <groupId>com.wyb.maven</groupId> -->
<artifactId>pro04-maven-module</artifactId>
<!-- <version>1.0-SNAPSHOT</version> -->
- 父工程依赖统一管理
父工程声明版本
<!-- 使用dependencyManagement标签配置对依赖的管理 -->
<!-- 被管理的依赖并没有真正被引入到工程 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.0.10</version>
</dependency>
</dependencies>
</dependencyManagement>
子工程饮用版本
<!-- 子工程引用父工程中的依赖信息时,可以把版本号去掉。 -->
<!-- 把版本号去掉就表示子工程中这个依赖的版本由父工程决定。 -->
<!-- 具体来说是由父工程的dependencyManagement来决定。 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
</dependencies>
4.2. Maven工程聚合关系
- 聚合:将多个项目组织到一个父级项目中,以便一起构建和管理的机制。聚合可以帮助我们更好地管理一组相关的子项目,同时简化它们的构建和部署过程。
- 聚合作用:
- 管理多个子项目:将多个子项目组织在一起,方便管理和维护。
- 构建和发布一组相关的项目:在一个命令中构建和发布多个相关的项目,简化了部署和维护工作。
- 优化构建顺序:对多个项目进行顺序控制,避免出现构建依赖混乱导致构建失败的情况。
- 统一管理依赖项:在父项目中管理公共依赖项和插件,避免重复定义。
- 聚合语法
父项目中包含的子项目列表
<project>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<packaging>pom</packaging>
<version>1.0.0</version>
<modules>
<module>child-project1</module>
<module>child-project2</module>
</modules>
</project>