maven(2)
maven依赖
在 pom.xml 中添加依赖项,需指定 groupId、artifactId、version(必要时还可配置 scope、exclusions 等):
<dependencies>
<!-- 示例:Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version> <!-- 版本号,可从 Maven 仓库查询 -->
</dependency>
<!-- 测试依赖(仅在测试时生效) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope> <!-- 作用域:test(测试)、compile(编译,默认)、provided(运行时提供)等 -->
</dependency>
</dependencies>
依赖作用域(Scope)
| 作用域 | 说明 | 示例场景 |
|---|---|---|
compile | 编译、测试、运行均有效(默认) | 业务代码依赖(如 Spring) |
test | 仅测试阶段有效(不包含在打包结果中) | JUnit 测试框架 |
provided | 编译和测试有效,但运行时由容器提供(如 Servlet API) | Web 容器内置依赖 |
runtime | 运行时需要(编译时不需要) | JDBC 驱动(编译时不需要类) |
system | 使用本地文件系统的依赖(需指定 systemPath) | 非 Maven 仓库的本地 JAR |
配置依赖仓库
1. 使用镜像仓库(加速下载)
在 settings.xml(用户级或全局)中配置镜像(如阿里云镜像):
<mirrors>
<mirror>
<id>alimaven</id>
<name>Aliyun Maven</name>
<url>https://maven.aliyun.com/repository/public</url> <!-- 最新公共镜像地址 -->
<mirrorOf>central</mirrorOf> <!-- 覆盖中央仓库 -->
</mirror>
</mirrors>
2. 添加私有仓库(如 Nexus/Artifactory)
在 pom.xml 或 settings.xml 中配置私有仓库:
<!-- 在 pom.xml 中配置(仅当前项目生效) -->
<repositories>
<repository>
<id>private-repo</id>
<name>Private Repository</name>
<url>http://your-private-repo.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled> <!-- 启用发布版本 -->
</releases>
<snapshots>
<enabled>false</enabled> <!-- 禁用快照版本 -->
</snapshots>
</repository>
</repositories>
四、IDEA 中操作依赖
1. 自动导入依赖
- 勾选 IDEA 右侧 Maven 面板中的
Import Maven projects automatically,修改pom.xml后自动刷新依赖。 - 手动刷新:点击 Maven 面板中的
Reload All Maven Projects图标(↻)。
依赖阻断
暴力
一、暴力阻断依赖的本质
在 Maven 中,暴力阻断依赖 通常指通过 强制覆盖版本 或 完全排除传递依赖 的方式,彻底解决依赖冲突问题,而不考虑下游模块的兼容性。这种方式适用于:
- 紧急修复生产环境依赖冲突
- 快速验证方案可行性
- 对第三方库依赖进行完全掌控
二、暴力阻断的典型场景与实现
1. 强制版本覆盖(最高优先级)
使用 <dependencyManagement> 强制所有传递依赖使用指定版本,即使存在冲突也会被直接覆盖。
<dependencyManagement>
<dependencies>
<!-- 强制所有传递依赖使用 Jackson 2.15.2 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- 完全排除某个依赖(通过指定不存在的版本) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>0.0.0-THIS-VERSION-NEVER-EXISTS</version>
</dependency>
</dependencies>
</dependencyManagement>
2. 递归排除所有传递依赖
在根依赖中使用 <exclusions> 排除所有传递依赖,然后手动引入需要的子依赖(风险极高)。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId> <!-- 排除所有传递依赖 -->
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 手动引入需要的子依赖(需精确控制) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>6.1.2</version>
</dependency>
3. 使用 <optional> 标记(切断传递路径)
将关键依赖标记为 optional,迫使下游模块必须显式声明依赖。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
<optional>true</optional> <!-- 下游模块必须手动引入 -->
</dependency>
4. 禁用特定仓库(阻止依赖解析)
在 settings.xml 中配置镜像,完全屏蔽某些仓库。
<mirrors>
<mirror>
<id>block-apache-repo</id>
<mirrorOf>apache.snapshots</mirrorOf> <!-- 屏蔽 Apache 快照仓库 -->
<url>http://0.0.0.0/blocked</url> <!-- 无效 URL,强制失败 -->
</mirror>
</mirrors>
举个例子Hello->HelloFriend->makeFriend 继承关系,当在HelloFriend里加上 <optional>true</optional>
在继承与hellofriend的makefriend就没有Hello了。 这种暴力的方法让所有继承hellofriend的子项目不能继承Hello。
三、暴力阻断的风险与权衡
| 优点 | 缺点 | 适用场景 |
|---|---|---|
| 快速解决依赖冲突 | 可能破坏下游模块兼容性 | 紧急修复生产环境问题 |
| 完全掌控依赖版本 | 增加维护成本(手动管理子依赖) | 内部项目或独立服务 |
| 强制统一依赖树 | 隐藏真实依赖问题(未根本解决) | 原型验证或短期项目 |
可选
这种情况下,用户尽在这个子项目中不能使用Hello依赖

仓库
仓库的概念
在 Maven 的术语中,仓库是一个位置(place)。
Maven 仓库是项目中依赖的第三方库,这个库所在的位置叫做仓库。
在 Maven 中,任何一个依赖、插件或者项目构建的输出,都可以称之为构件。
Maven 仓库能帮助我们管理构件(主要是JAR),它就是放置所有JAR文件(WAR,ZIP,POM等等)的地方。
仓库的类型有:
- 本地(local)
- 中央(central)
- 远程(remote)
本地仓库
Maven 的本地仓库,在安装 Maven 后并不会创建,它是在第一次执行 maven 命令的时候才被创建。
运行 Maven 的时候,Maven 所需要的任何构件都是直接从本地仓库获取的。如果本地仓库没有,它会首先尝试从远程仓库下载构件至本地仓库,然后再使用本地仓库的构件。
默认情况下,不管Linux还是 Windows,每个用户在自己的用户目录下都有一个路径名为 .m2/respository/ 的仓库目录
Maven 本地仓库默认被创建在 %USER_HOME% 目录下。要修改默认位置,在 %Maven_HOME%\conf 目录中的 Maven 的 settings.xml 文件中定义另一个路径。

中央仓库
Maven 中央仓库是由 Maven 社区提供的仓库,其中包含了大量常用的库。
中央仓库包含了绝大多数流行的开源Java构件,以及源码、作者信息、SCM、信息、许可证信息等。一般来说,简单的Java项目依赖的构件都可以在这里下载到。
中央仓库的关键概念:
- 这个仓库由 Maven 社区管理。
- 不需要配置。
- 需要通过网络才能访问。
依赖搜索顺序

生命周期
生命周期的概念
Maven的生命周期是对所有的构建过程进行抽象和统一。Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作,生命周期只是定义了一系列的阶段,并确定这些阶段的执行顺序。而在执行这些阶段时,实际的工作还是由插件来完成的。这种思想与设计模式中的模板方法非常相似。
Maven有三套相互独立的生命周期:
- Clean
-
- clean生命周期的目的是清理项目
-
- Default
-
- default生命周期的目的是构建项目
-
- site
-
- site生命周期的目的是建立项目站点。
-
完整生命周期
|
生命周期 |
clean |
default |
site |
|
阶段(phase),执行顺序由上至下 |
pre-clean |
validate |
pre-site |
|
clean |
initialize |
site | |
|
post-clean |
generate-sources |
post-site | |
|
|
process-sources |
site-deploy | |
|
generate-resources |
| ||
|
process-resources | |||
|
compile | |||
|
process-classes | |||
|
generate-test-sources | |||
|
process-test-sources | |||
|
generate-test-resources | |||
|
process-test-resources | |||
|
test-compile | |||
|
process-test-classes | |||
|
test | |||
|
prepare-package | |||
|
package | |||
|
pre-integration-test | |||
|
integration-test | |||
|
post-integration-test | |||
|
verify | |||
|
install | |||
|
deploy |
用户在mvn命令后可以指定三个生命周期中的任何阶段,则Maven会按以下逻辑执行:首先会得到该阶段所属生命周期,从该生命周期中的第一个阶段开始按顺序执行,直至该阶段本身。例如执行mvn clean命令会依次执行clean生命周期中的pre-clean阶段及clean阶段。mvn命令后可以指定多个阶段,Maven会按照输入的顺序依次执行,每次执行都会按照之前描述的逻辑执行。
之前提到实际的工作还是由插件来完成的,这意味着插件需要和阶段绑定起来。Maven已经事先将很多核心插件绑定到对应的阶段,这样用户几乎不用配置就有构建Maven项目。Maven的内置绑定如下:
|
生命周期 |
阶段(phase) |
插件目标 |
|
clean |
clean |
maven-clean-plugin:clean |
|
default |
process-resources |
maven-resources-plugin:resources |
|
compile |
maven-compiler-plugin:compile | |
|
generate-test-resources |
maven-resources-plugin:testResouces | |
|
test-compile |
maven-compiler-plugin:testCompile | |
|
test |
maven-surefire-plugin:test | |
|
package |
打包类型是jar时:maven-jar-plugin:jar; | |
|
打包类型是war时:maven-war-plugin:war | ||
|
install |
maven-install-plugin:install | |
|
deploy |
maven-deploy-plugin:deploy | |
|
site |
site |
maven-site-plugin:site |
|
site-deploy |
maven-site-plugin:deploy |
Maven继承和聚合
继承的意义
继承就是避免重复,maven的继承也是这样,它还有一个好处就是让项目更加安全。比如我们在项目开发的过程中,可能多个模块独立开发,但是多个模块可能依赖相同的公共模块,比如说每个模块都需要javaseo-utils,在编译的时候,maven-compiler-plugin插件也要被引入,maven仓库地址以及发布目录都是相同的配置。我们可以使用Maven的继承功能,把公共的配置信息写到父模块中,子模块只要继承了该父模块,也会继承父模块的配置信息。
可继承的POM元素
groupId :项目组 ID ,项目坐标的核心元素;
version :项目版本,项目坐标的核心元素;
description :项目的描述信息;
organization :项目的组织信息;
inceptionYear :项目的创始年份;
url :项目的 url 地址
develoers :项目的开发者信息;
contributors :项目的贡献者信息;
distributionManagerment :项目的部署信息;
issueManagement :缺陷跟踪系统信息;
ciManagement :项目的持续继承信息;
scm :项目的版本控制信息;
mailingListserv :项目的邮件列表信息;
properties :自定义的 Maven 属性;
dependencies :项目的依赖配置;
dependencyManagement :醒目的依赖管理配置;
repositories :项目的仓库配置;
build :包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等;
reporting :包括项目的报告输出目录配置、报告插件配置等。
IDEA实现Maven的继承
创建父类项目


创建子类项目core 

以同样的方式创建manage和portal项目:

至此,一个由parent统一管理core,manage和portal的mavan项目就创建好了;
观察父子项目的pom文件配置

继承的依赖管理
父类直接引用依赖,如果在父类的dependencies内直接引用依赖,则子类都会继承该依赖,以mybatis为例:

父类通过dependencyManagement管理依赖,子类不会默认继承该依赖,但是当子类使用该依赖时无需考虑版本信息,直接继承父类dependencyManagement中设置的版本号(Version),以log4j为例:

聚合管理
我们在平时的开发中,项目往往会被划分为好几个模块,比如common公共模块、system系统模块、log日志模块、reports统计模块、monitor监控模块等等。这时我们肯定会出现这么一个需要,我们需要一次构件多个模块,而不用每个模块都去mvn;
以上面得父子项目为例,当我们对parent进行mvn install时,会对core,manage和portal项目均进行install操作:

properties属性的使用
通过 properties元素用户可以定义一个或多个 maven 属性,然后在 maven 的其他地方使用 ${属性名称} 的方式引用该属性,这种做法的意义在于消除重复和统一管理。比如,需要在多个地方重复声明同样的 SpringFramework 版本,现在只需要在一个地方声明就可以。

更多推荐

所有评论(0)