maven
Maven
Maven是一个Java项目管理和构建的工具,它可以定义项目结构、项目依赖管理、使用统一的方式进行自动化构建,是Java项目不可或缺的工具。
maven的作用
- 提供了一套标准化的项目结构。
- 以前不用的开发工具项目结构不一样,maven出现后规范了项目结构,开发人员上手项目变得更加简单。

-
提供了一套标准化的构建流程(编译,测试,打包,发布...)。
![image-20250921132547791]()
-
提供了一套依赖管理机制(pom.xml文件,管理项目中的所有jar包)。
- 使用传统的项目开发,每次都要复制jar包到lib目录,如果jar包很多,项目大小会很大,且多个项目的话,使用同一个包需要复制多份。
- maven管理后,所有jar包都存在maven仓库,只需要用pom.xml管理jar包。
- 解决jar包和jar包的版本冲突问题(利用"依赖传递"特性解决)。
Maven下载和配置
Maven下载和配置 简要步骤及注意事项:
-
maven是一个java工具,它必须有java环境,配置java环境保留。
-
下载版本可参考idea默认绑定的maven版本。
-
修改配置:主要修改镜像和仓库位置。
-
Maven 中央仓库:默认运程仓库是 Maven 中央仓库(repo.maven.apache.org),它是官方的、最全的公共仓库,但服务器在国外,国内访问速度可能较慢。
-
镜像:Maven 中央仓库(Central Repository)在国内的一个“完整拷贝”(或称“镜像”),定期同步,以保证内容一致。
-
镜像的作用:拦截原本对Maven 中央仓库的请求,并将其重定向到镜像地址。对用户来说,这个过程是透明的,感觉不到区别,由于镜像在国内,下载速度会快很多。
-
-
IDEA配置Maven。
创建Maven项目
maven命令创建
-
mvn archetype:generate
idea创建

Maven项目结构
另外还有一个target目录专门存放构建操作输出的结果。
约定目录结构的意义
Maven为了让构建过程能够尽可能自动化完成,所以必须约定目录结构的作用。例如: Maven执行编译操作,必须先去Java源程序目录读取Java源代码,然后执行编译,最后把编译结果存放在target目录。
约定大于配置
Maven对于目录结构这个问题,没有采用配置的方式,而是基于约定。这样会让我们在开发过程中非常方便。如果每次创建Maven工程后,还需要针对各个目录的位置进行详细的配置,那肯定非常麻烦。
目前开发领域的技术发展趋势就是:约定大于配置,配置大于编码。
Maven命令
命令行:注意要在pom.xml所在的目录下执行命令
idea自带的界面执行:

生命周期:例如执行compile时,其实会依次执行 clean、valiate、compile
Maven 生命周期命令作用:
clean - 清理项目,删除target目录
validate - 验证项目正确性和所需信息是否可用
compile - 编译项目源代码
test - 运行单元测试
package - 打包编译后的代码(jar、war等格式)
verify - 检查集成测试结果以确保质量标准
install - 将包安装到本地仓库,供其他项目使用
site - 生成项目站点文档
deploy - 将最终包复制到远程仓库
这些命令按顺序执行,构成Maven的标准构建生命周期。
依赖范围
依赖范围:compile(默认)、provided、runtime、system、test
有哪些范围:测试(main.java)、编译(test.java)、运行/打包(包内)
-
test: 编译× 测试✔ 打包×
- 例如:junit 测试的时候才能用(main.java文件夹下的能用),编译、打包不能用。
-
provided:编译✔ 测试✔ 打包×
- 例如:javax.servlet(一般用tomcat启动,tomcat里已经有了javax.servlet,项目打包不用带这个包了,带了反而可能导致servlet版本混乱、项目增大)。
-
compile:编译✔ 测试✔ 打包✔
- 默认的。
-
runtime:编译× 测试✔ 打包✔
- 反射 数据库驱动class.forName()。
-
system:效果等于provided,但是其不会依赖仓库中jar包,而是引用本地物理路径的jar包 。
-
基本不会使用,了解即可。
-
使用时配合一个
使用。
-
1.首先﹑依赖范围建议﹑哪怕所有的范围都设置compile,也不会影响功能正常使用。
2.使用依赖提供的scope,直接中央仓库无脑复制就行了,并且idea也会自动补全。
3.90%以上都会使用compile。
4.但是如果做一个好的程序员,应该尽量让程序优雅,保证依赖的最小范围。
依赖传递

<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.40</version>
<! --作用访问是test、provided 就不会传递
<scope>provided</scope>
-->
<!--是否传递 默认是于false 会传递-->
<optional>false</optional>
</dependency>
</dependencies>
依赖的排除和覆盖
<!-- com.test.project 里面有一个依赖我们不需要的情况,或者版本不需要的情况,用下面的方式解决-->
<dependency>
<groupId>com.test</groupId>
<artifactId>bproject</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 手动排除
<exclusions>
<exclusion>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</exclusion>
</exclusions>
-->
</dependency>
<!--在自己的工程添加一个系统的依赖,不同版本会以我们工程依赖优先进行替换-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
依赖图
商业版的idea才有

Maven聚合和继承
聚合:主要关注的是项目的物理结构和构建过程。
- 将多个独立的 Maven 项目(模块)组合在一起,以便通过一个统一的入口(父 POM)来一次性构建所有这些项目。
- 子项目直接可以互相直接引用,而不需要install
继承:主要关注的是POM 配置的逻辑关系和复用性。
- 允许子模块 POM 从一个共同的父 POM 中继承配置信息,从而实现配置的复用和统一管理。
聚合
聚合项目:
-
把src删掉,因为聚合项目通常只是管理子工程。
-
把packaging修改下默认jar,改成pom,当前不是一个具体的包。
-
把子工程管理起来。
<packaging>pom</packaging>
<modules>
<module>maven_01</module>
<module>maven_02</module>
</modules>
继承
<parent>
<groupId>org.example</groupId>
<artifactId>MavenTest</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
Maven命令复制依赖
dependency:copy-dependencies:用于将项目依赖的jar包从仓库拷贝到指定目录。
-
如果子工程都没引入其他的依赖:
-
例如父工程引入
5.8.40 ,子过程都没引入其他版本。 -
那么复制过来的就都是父工程配置的依赖:
5.8.40 。
-
-
如果一个子工程引入其他的依赖,其他用父工程的:
- 例如父工程引入
5.8.40 ,子工程1未引入,直接用父工程的,子工程25.8.39 。 - 那么复制过来的就都是父工程配置的和子工程2配置的依赖:
5.8.40 、5.8.39 。
- 例如父工程引入
-
如果所有子工程引入新的版本,但是都是同一个:
-
例如父工程
5.8.40 ,所有子工程包括子过程1和子工程2都引入5.8.38 。 -
那么复制过来的就都是子过程1和子工程2配置的依赖:
5.8.38 。 -
如果所有子工程引入新的版本,但是不是同一个:
- 例如父工程
5.8.40 ,子工程15.8.38 ,子工程25.8.39 。 - 那么复制过来的就是子过程1和子工程2配置的依赖:
5.8.38 、5.8.39 。
- 例如父工程
总结就是:【父工程】的依赖会传递给【子工程】用,但是【子工程】重新导入的依赖会覆盖【父工程】传递过来的。
另外:如果所有【子工程】都覆盖了【父工程】传递过来的依赖,那么【父工程】配置的这个依赖相当于没有用,dependency:copy-dependencies也就不会复制出来这个【父工程】配置的无用依赖。
mvn clean install dependency:copy-dependencies -DoutputDirectory=D:\file\IDEA_File\mylib -DincludeScope=compile -Dsilent=true -Dmdep.cpPom=false -DskipTests -T 4
mvn clean install dependency:copy-dependencies -DoutputDirectory=D:\file\IDEA_File\mylib -DincludeScope=compile -Dsilent=true "-Dmdep.cpPom=false" -DskipTests -T 4
// 会把父工程和子过程里面所有导入的依赖里的jar包复制到D:\ToolOfProductionData\IDEAFile\MavenTest\mylib中
// 如果子工程都没引入其他的依赖:那么复制过来的就都是父工程配置的依赖
// 如果子工程引入的版本都是同一个:例如父工程
mvn clean install dependency:copy-dependencies -DoutputDirectory=D:\ToolOfProductionData\IDEAFile\MavenTest\mylib -DincludeScope=compile -Dsilent=true "-Dmdep.cpPom=false" -DskipTests -T 4
pom.xml文件解析
父工程
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 无视 maven版本相关 -->
<modelVersion>4.0.0</modelVersion>
<!-- 坐标信息 本工程的坐标信息 每个项目都有一个唯一的坐标信息 -->
<!--
怎么配置本工程的坐标信息:
项目:
groupId: 域名反过来 com.baidu
artifactId: 项目名字
version: 版本 1.0-SNAPSHOT SNAPSHOT:还没上线的最初的快照版本
模块:前台、后台、公共模块
groupId: 域名反过来+项目名字 com.baidu.项目名字
artifactId: 模块名字
version: 版本 1.0-SNAPSHOT SNAPSHOT:还没上线的最初的快照版本
-->
<groupId>org.example</groupId>
<artifactId>MavenTest</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 设置打包方式 默认是jar 常用的:jar war pom -->
<packaging>pom</packaging>
<modules>
<module>maven_01</module>
<module>maven_02</module>
</modules>
<!-- 属性 变量
通常设置依赖的版本:统一管理版本
-->
<properties>
<!-- 当前jdk版本 其实一般不会在这里设置,idea启动项目里面已经设置了,其实这里可以删除 -->
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!-- 编码设置 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 设置依赖的版本 -->
<javax.servlet.version>3.1.0</javax.servlet.version>
</properties>
<!-- 通过坐标信息引用jar包,准确说是引入依赖,因为一个依赖会有多个jar包 -->
<!-- 找依赖的地址: https://mvnrepository.com/ -->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet.version}</version>
<!--
依赖范围:compile(默认)、provided、runtime、system、test
有哪些范围:测试(main.java)、编译(test.java)、运行/打包(包内)
test: 编译× 测试✔ 打包× 例如:junit 测试的时候才能用(main.java文件夹下的能用),编译、打包不能用
provided:编译✔ 测试✔ 打包× 例如:javax.servlet(一般用tomcat启动,tomcat里已经有了javax.servlet,项目打包不用带这个包了,带了反而可能导致servlet版本混乱、项目增大)
compile:编译✔ 测试✔ 打包✔ 默认的
runtime:编译× 测试✔ 打包✔ 反射 数据库驱动class.forName()
system:基本不会使用,了解即可 效果等于provided,但是其不会依赖仓库中jar包,而是引用本地物理路径的jar包 使用时配合一个<systemPath></systemPath>使用
1.首先﹑依赖范围建议﹑哪怕所有的范围都设置compile,也不会影响功能正常使用。
2.使用依赖提供的scope,直接中央仓库无脑复制就行了,并且idea也会自动补全。
3.90%以上都会使用compile。
4.但是如果做一个好的程序员,应该尽量让程序优雅,保证依赖的最小范围。
-->
<scope>compile</scope>
</dependency>
</dependencies>
<!-- 对于子工程必须要的依赖,可以放在dependencies这里,直接传递给子项目-->
<!-- 对于子工程不是必须要的依赖,可以放在dependencyManagement这里,子工程引入时不需要版本,因为这里控制了-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.40</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
子工程1
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>MavenTest</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>maven_01</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>
</dependencies>
</project>
子工程2
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.example</groupId>
<artifactId>MavenTest</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>maven_02</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>
下载依赖流程

# 没有镜像时的完整流程
开始下载依赖
↓
1. 检查本地仓库 (~/.m2/repository)
├── 存在 → 直接使用,结束
└── 不存在 → 继续
↓
2. 按顺序访问 pom.xml 中配置的 <repositories>
├── 第1个repository → 直接访问其URL
├── 第2个repository → 直接访问其URL
├── ...
└── 最后一个repository → 直接访问其URL
↓
3. 中央仓库(默认存在)
└── 直接访问 https://repo.maven.apache.org/maven2/
↓
4. 找到依赖 → 下载到本地
所有仓库都没找到 → 报错
# 配置镜像时的完整流程
开始下载依赖
↓
1. 检查本地仓库 (~/.m2/repository)
├── 存在 → 直接使用,结束
└── 不存在 → 继续
↓
2. 按顺序访问 pom.xml 中配置的 <repositories>
├── 第1个repository → 是否配置镜像 → 否就直接访问其URL,是就镜像拦截: 实际访问镜像配置的URL
├── 第2个repository → 是否配置镜像 → 否就直接访问其URL,是就镜像拦截: 实际访问镜像配置的URL
├── ...
└── 最后一个repository → 是否配置镜像 → 否就直接访问其URL,是就镜像拦截: 实际访问镜像配置的URL
↓
3. 中央仓库(默认存在)
└── → 是否配置镜像 → 否直接访问 https://repo.maven.apache.org/maven2/,是就镜像拦截: 实际访问镜像配置的URL
↓
4. 找到依赖 → 下载到本地
所有仓库都没找到 → 报错
参考
参考视频:7、依赖引用_哔哩哔哩_bilibili
镜像和repositories
<!-- 项目的pom.xml -->
<repositories>
<repository>
<id>private</id>
<name>自研私有库</name>
<url>https://xxx/repositories/releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>central</id>
<name>阿里云公共库</name>
<url>https://xxx/repository/public</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring</id>
<name>阿里云spring仓库</name>
<layout>default</layout>
<url>https://xxx/repository/spring</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<!-- 最后会有一个隐含的中央仓库 id叫central -->
<!--
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
-->
</repositories>
<!-- Maven的settings.xml -->
<mirrors>
<mirror>
<id>mirrorId</id>
<!-- mirrorOf配置*表示所有仓库 -->
<!-- <mirrorOf>*,!repo1</mirrorOf> 这样配置表示,除了repo1,都重定向到<url>http://my.repository.com/repo/path</url>-->
<mirrorOf>repositoryId</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://my.repository.com/repo/path</url>
</mirror>
</mirrors>
<mirrorOf>repositoryId</mirrorOf>里面repositoryId配置*:
- 项目的pom.xml 里面配置的所有的
,都重定向到 <url>http://my.repository.com/repo/path</url>
<mirrorOf>repositoryId</mirrorOf>里面repositoryId配置对应
- 项目的pom.xml 里面配置的id,重定向到
<url>http://my.repository.com/repo/path</url>
浙公网安备 33010602011771号