聊聊Maven的依赖传递、依赖管理、依赖作用域

2023年 10月 12日 50.4k 0

1. 依赖传递

在Maven中,依赖是会传递的,假如在业务项目中引入了spring-boot-starter-web依赖:


    org.springframework.boot
    spring-boot-starter-web
  	2.7.4

那么业务项目不仅直接引入了spring-boot-starter-web依赖,还间接引入了spring-boot-starter-web的依赖项:

spring-boot-starterspring-boot-starter-jsonspring-boot-starter-tomcatspring-webspring-webmvc

Maven依赖关系如下图所示:

聊聊Maven的依赖传递、依赖管理、依赖作用域-1

外部库如下图所示:

聊聊Maven的依赖传递、依赖管理、依赖作用域-2

其中,业务项目对spring-boot-starter-web的依赖称为直接依赖,对spring-boot-starter-web的依赖项:

spring-boot-starterspring-boot-starter-jsonspring-boot-starter-tomcatspring-webspring-webmvc

的依赖称为间接依赖。

聊聊Maven的依赖传递、依赖管理、依赖作用域-3

2. 依赖管理

dependencyManagement元素主要用来统一管理依赖项的版本号。

假如父项目的pom文件中声明了如下依赖:


    
        
            org.apache.commons
            commons-collections4
            4.4
        
    
    

那么子项目在添加该依赖时,可以不指定版本号:


		
        org.apache.commons
        commons-collections4
    

Maven会自动找到父项目中声明的该依赖项的版本号,如下图所示:

聊聊Maven的依赖传递、依赖管理、依赖作用域-4

聊聊Maven的依赖传递、依赖管理、依赖作用域-5

这样的优点是可以统一在父项目中管理依赖项的版本号,如果需要升级版本,只需改动父项目一个地方即可,子项目不用改动。

说明:

1)dependencyManagement只是声明依赖项,并没引入依赖项,子项目仍需显式引入,不过可以不指定版本号

2)如果子项目不想使用继承的父项目中的版本号,在子项目中指定版本号即可

3. 依赖作用域

在Maven中,可以使用scope来指定当前依赖项的作用域,常见的值有:compile、provided、runtime、test、import等,如下所示:


    junit
    junit
    test

3.1 compile

compile是默认的作用域,如果引入依赖时,没有明确指定作用域,则依赖作用域为compile。

作用域为compile的依赖,在编译、测试和运行时都是可用的,并且会参与项目的打包过程,该依赖会传递给依赖该模块的其他模块。

3.2 provided

作用域为provided的依赖,在编译和测试时是可用的,在运行时是不可用的,不会参与项目的打包过程,也不会传递给其他模块。

比如lombok依赖会在编译时生成相应的get、set等方法,在运行时就不需要这个依赖了,因此常常被指定为provided:


    org.projectlombok
    lombok
    1.18.16
    provided

因为被指定为provided,项目打包时是不包含lombok依赖项的,如下图所示:

聊聊Maven的依赖传递、依赖管理、依赖作用域-6

如果将上面的代码provided删除的话,运行时是下图这样的:

聊聊Maven的依赖传递、依赖管理、依赖作用域-7

以上验证需将项目打包方式改为war,打包后查看WEB-INF/lib目录

聊聊Maven的依赖传递、依赖管理、依赖作用域-8

3.3 runtime

作用域为runtime的依赖,在测试和运行时是可用的,在编译时是不可用的,会参与项目的打包过程,也会传递给依赖该模块的

其他模块。

说明:

作用域为runtime的依赖中的类,在项目代码里不能直接用,用了无法通过编译(这里指的是在src/main/java下使用)。

以mysql-connector-java为例,假如引入依赖时是下面这样的:


    mysql
    mysql-connector-java
    8.0.30

下面的示例代码是可以编译通过的:

聊聊Maven的依赖传递、依赖管理、依赖作用域-9

如果将作用域修改为runtime,上面的示例代码无法通过编译:


    mysql
    mysql-connector-java
    8.0.30
    runtime

聊聊Maven的依赖传递、依赖管理、依赖作用域-10

3.4 test

作用域为test的依赖,只在测试时可用(包括测试代码的编译、执行),不会参与项目的打包过程,也不会传递给其他模块。

常见的有junit、mockito等:


    junit
    junit
    4.12
    test

因为被指定为test,项目打包时是不包含junit依赖项的,如下图所示:

聊聊Maven的依赖传递、依赖管理、依赖作用域-11

如果将上面的代码test删除的话,运行时是下图这样的:

聊聊Maven的依赖传递、依赖管理、依赖作用域-12

以上验证需将项目打包方式改为war,打包后查看WEB-INF/lib目录

聊聊Maven的依赖传递、依赖管理、依赖作用域-13

说明:

作用域为test的依赖中的类或者注解只能在src/test/java下才可以使用,在src/main/java下无法使用,如junit包下的@Test注解和org.junit.Assert断言类。

3.5 import

每个项目,一般都会继承自一个父项目,在实际的工作中,这个父项目一般都是公司架构组提供的带有公司特色的一个基础项目,

当然也可以是spring boot官方的项目。

以spring boot官方的项目为例:


    org.springframework.boot
    spring-boot-starter-parent
    2.7.4

这个父项目中,会使用dependencyManagement标签对依赖项的版本统一管理,子项目中,可以按需引入父项目

dependencyManagement中定义的依赖,但可以不指定版本号(版本号会自动继承父项目中定义的版本号)。

但是存在以下2个问题:

  • Maven是单继承的,一个项目只能有一个parent项目
  • parent项目dependencyManagement中的依赖项会越来越多,不好管理
  • 依赖作用域import的出现就是为了解决以上问题,它可以通过非继承的方式批量引入另一个依赖项中

    dependencyManagement元素中定义的依赖项,如下所示:

    
        
          org.springframework.session
          spring-session-bom
          ${spring-session-bom.version}
          pom
          import
        
      
    
    

    说明:import只能用在dependencyManagement下type为pom的dependency中。

    以上代码等价于添加了以下6个依赖项:

    聊聊Maven的依赖传递、依赖管理、依赖作用域-14

    可以看出,使用import可以模块化的管理依赖项,提高复用性,pom文件也更加简洁。

    3.6 区别

    综上所述,各个依赖作用域的区别如下表所示:

    scope取值 编译时可用 测试时可用 运行时可用 是否参与打包 依赖传递
    compile
    provided × × ×
    runtime ×
    test × × × ×

    4. 影响依赖传递的因素

    4.1 依赖作用域(scope)

    依赖作用域会影响依赖传递,从上表可以看出,如果scope为provided或者test,该依赖不会传递,只有scope为compile或者runtime,

    该依赖才会传递。

    4.2 可选依赖(optional)

    通过dependency标签引入依赖时,可以通过指定该依赖是不是可选的,默认值为false:

    
        org.ehcache
        ehcache
    	  3.2.3
        true
    
    

    如果值为true,那么这个依赖不会传递。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论