maven依赖管理和生命周期


🌈 个人主页: Hygge_Code
🔥 热门专栏:从0开始学习Java | Linux学习| 计算机网络
💫 个人格言: "既然选择了远方,便不顾风雨兼程"

文章目录

依赖管理

依赖指的是当前项目运行所需要的jar包,一个项目可以有很多个依赖。

依赖传递🤔

依赖具有传递性:

  • 直接依赖:在当前项目中,通过依赖配置建立的依赖关系
  • 间接依赖:被依赖的资源,如果还依赖其他资源,那么当前项目间接依赖其他资源

示例:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
</dependencies>

编写了上面的依赖代码后,产生了下图的依赖文件

依赖冲突问题解决🐦‍🔥

依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突

示例代码:

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>

通过查看依赖,我们发现spring-aopspring-context都依赖了一个叫spring-core的依赖。此时spring-core的版本有两个,这就产生了依赖冲突。

可以看出,以上产生的依赖冲突由maven自行解决了。


下面我们来看依赖冲突是如何解决的:

1. 间接依赖 - 声明优先

**规则:**谁先定义的就用谁的传递依赖(间接依赖),即在pom.xml文件自上而下,先声明的jar坐标,就先引用该jar的传递依赖。

原示例代码引入的两个依赖包中均包含spring-corespring-beans(都属于间接依赖),而由于直接依赖sping - aop先被声明使用,所以spring - aop中的间接依赖优先于后面声明使用的 spring-beans中的间接依赖。

因此我们如果要使用5.2.0版本的spring core包,我们可以改成如下声明:

xml 复制代码
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

2. 直接依赖高于间接依赖

**规则:**直接依赖高于间接依赖

这里还是基于原示例代码讲解:

最先声明使用的spring-context依赖里含有spring-aop依赖(间接依赖),但使用的却是下面的spring-aop,这是因为下面声明定义的spring-aop依赖为直接依赖,而直接依赖的优先级高于间接依赖。

3. 排除依赖原则

**规则:**在不影响项目运行的情况下,如果依赖冲突,可以把被冲突的依赖排除掉,注意排除的依赖不需要添加依赖的版本号 【使用exclusion】

xml 复制代码
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.7.RELEASE</version>
    <exclusions>
        <exclusion>
            <artifactId>spring-core</artifactId>
            <groupId>org.springframework</groupId>
        </exclusion>
    </exclusions>
</dependency>

添加了exclusion部分后,去掉了spring-context中包含的依赖spring-core

4. 版本锁定

**规则:**使用 dependencyManagement 进行版本锁定

dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,如果我们项目中只想使用spring core 5.2.0的包,pom.xml可以改为如下:

xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>

可以看到,spring-core的依赖从原示例代码版本的5.2.7变为了5.2.0

依赖范围(使用scope指定范围)🥝

Maven 的依赖范围(Dependency Scope) 是用来控制依赖在项目构建的不同阶段(编译、测试、运行)是否生效,以及依赖是否会被传递的核心机制。它解决了"不同环境需要不同依赖"的问题(比如测试依赖不需要打包到最终产物中),同时也能避免依赖冲突和冗余。

Maven 构建生命周期主要分为 3 个核心阶段:

  • 编译(compile) :项目主代码(src/main/java)的编译
  • 测试(test) :测试代码(src/test/java)的编译和运行
  • 运行(runtime):项目运行时(如打包后的 jar/war 运行)

依赖范围本质上是定义:该依赖在哪些阶段可见,是否会被传递给下游项目,是否会被打包到最终产物中

常用依赖范围 📖

以下是 Maven 4种常用的依赖范围:

范围 编译主代码 测试代码 运行时 传递性 打包到产物 典型场景
compile 核心业务依赖(如 Spring Core)
test 测试框架(JUnit、TestNG)
runtime 运行时依赖(如 JDBC 驱动)
provided 容器提供的依赖(如 Servlet API)
1. compile(默认范围)🍋‍🟩
  • 含义:默认的依赖范围,适用于所有构建阶段(编译、测试、运行)。

  • 特点

    • 主代码和测试代码都能引用该依赖;
    • 依赖会被传递(下游项目引入当前项目时,该依赖会自动引入);
    • 最终会被打包到 jar/war 等产物中。
  • 示例

    xml 复制代码
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.1.0</version>
        <!-- 省略 scope,默认 compile -->
    </dependency>
2. test 🍋‍🟩
  • 含义:仅用于测试阶段(测试代码的编译和运行),主代码不可见。

  • 特点

    • 主代码(src/main)无法引用该依赖;
    • 不传递(下游项目不会继承该依赖);
    • 不会被打包到最终产物中。
  • 示例

    xml 复制代码
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope> <!-- 仅测试用 -->
    </dependency>
3. runtime🍋‍🟩
  • 含义:编译主代码时不需要,但运行时(包括测试运行)需要。

  • 特点

    • 主代码编译时无法引用(比如 JDBC 驱动,编译时只需要接口,运行时需要实现);
    • 测试代码和运行时可见;
    • 会被传递,且打包到产物中。
  • 示例

    xml 复制代码
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
        <scope>runtime</scope> <!-- 仅运行时需要 -->
    </dependency>
4. provided🍋‍🟩
  • 含义:编译和测试阶段需要,但运行时由容器/环境提供(无需打包)。

  • 应用场景

    • Web 项目中的 Servlet API(Tomcat 等容器已自带);
  • 特点

    • 编译/测试可见,运行时不可见;
    • 不传递,不打包(避免和容器依赖冲突)。
  • 示例

    xml 复制代码
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope> <!-- 容器提供 -->
    </dependency>

声明周期

Maven对项目周期的构建分为3个🧾

clean: 清理工作阶段
default:核心工作阶段。比如编译、测试、打包、部署等
site: 产生报告,发布站点等

1. clean生命周期

  • pre-clean 执行一些需要在clean之前完成的工作
  • clean 移除所有上一次构建生成的文件
  • post-clean 执行一些需要在clean之后立刻完成的工作

2. default生命周期

3. site生命周期

  • pre-site 执行一些需要在生成站点文档之前完成的工作
  • site 生成项目的站点文档
  • post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
  • site-deploy 将生成的站点文档部署到特定的服务器

插件

**介绍:**插件与生命周期内的阶段绑定,在执行到对应生命周期时,执行对应的插件功能,默认maven在各个生命周期阶段上绑定有预设功能。

我们也可以通过插件可以自定义其他功能,下面我们写一个自定义插件---在生成测试代码的时候,给主程序源代码打包、同时给测试源代码打包:

xml 复制代码
<build>
  <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>2.2.1</version>

        <!-- 自定义插件的执行逻辑 -->
        <executions>
            <execution>
                <goals>
                    <!-- 生成「主源码包」(src/main/java 下的源码) -->
                    <goal>jar</goal>
                    <!-- 生成「测试源码包」(src/test/java 下的源码) -->
                    <goal>test-jar</goal>
                </goals>
                <!-- 绑定执行时机:到 generate-test-resources 阶段 -->
                <phase>generate-test-resources</phase>
            </execution>
        </executions>
     </plugin>
  </plugins>
</build>

测试结果如下:


如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!

相关推荐
Z_W_H_2 小时前
MyBatis-Plus 详细学习文档
学习·mybatis
小六花s2 小时前
渗透测试前四天PHP文件包含笔记
android·学习·渗透测试
秋深枫叶红2 小时前
嵌入式第四十七篇——ARM汇编
汇编·arm开发·学习
散峰而望2 小时前
OJ 题目的做题模式和相关报错情况
java·c语言·数据结构·c++·vscode·算法·visual studio code
长安城没有风2 小时前
Java 高并发核心编程 ----- 初识多线程(上)
java·juc
rannn_1112 小时前
【Javaweb学习|Day7】事务管理、文件上传
后端·学习·javaweb
董世昌412 小时前
HTTP协议中,GET和POST有什么区别?分别适用什么场景?
java·开发语言·前端
独自破碎E2 小时前
Java中HashMap的默认负载因子为什么设置为0.75?
java·开发语言·网络
疋瓞2 小时前
C/C++查缺补漏《5》_智能指针、C和C++中的数组、指针、函数对比、C和C++中内存分配概览
java·c语言·c++