依赖概念
依赖范围
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<!--依赖作用范围-->
<scope>test</scope>
</dependency>
mvn在工作的不同生命周期中依赖的classpath是不同,分为编译-compile,测试-test和运行时-runtime三种不同的classpath,依赖范围scope标签就是用来控制依赖与三种不同的classpath的关系的,以让合适的依赖在合适的时候被引入。
scope可选依赖范围
-
compile:编译依赖范围,没有指定scope时的默认值。此范围依赖会在三种classpath都有效。
-
test:测试依赖范围,只有在测试时有效,如上面的junit。
-
provide:以提供依赖范围,编译和测试时有效,运行时无效。如servlet-api,容器提供了,但是在编译和测试要用。
-
runtime:运行时依赖范围,测试和运行时范围有效,编译代码时无效。如jdbc驱动,只有在测试和运行时代码调用时才会用到。
-
system:系统依赖范围,编译和测试时有效,运行时无效,用于导入第三方不在依赖库中的依赖,jar包放在本机路径,通过SystemPath指定
<dependency> <groupId>com.github.nintha</groupId> <artifactId>webp-imageio-core</artifactId> <version>0.1.0</version> <scope>system</scope> <systemPath>${project.basedir}/lib/webp-imageio-core-0.1.0.jar</systemPath> </dependency> -
import:导入依赖范围,对三种classpath没有实际影响,主要是用在dependencyManagement中,用于合并目标pom的dependencyManagement依赖配置到当前pom的dependencyManagement,如:下面就是导入springboot的依赖配置管理信息。
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-parent</artifactId> <version>2.2.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

传递性依赖
项目中直接引入依赖时,会自动引入直接依赖所依赖的依赖的特性。
传递性依赖和依赖范围的关系
例如:A依赖于B,B依赖于C
A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖
下图表示了在传递性依赖引入时,不同的第一直接依赖范围和第二直接依赖范围得出的传递性依赖范围结果,左侧第一列为第一直接以来范围,上方第一行为第二直接依赖范围,交叉单元格为传递性依赖结果(空白代表无传递性依赖):

依赖调解
当同一个依赖的不同版本被引入时,需要决定最终使用的版本,这就是依赖调解,maven提供了一些默认的调解规则。
调解规则,按优先顺序:
-
路径最近者优先原则
如:存在两个依赖关系,A->B->C->X(1.0)和A->B->X(2.0),此时X依赖的版本1.0和2.0同时被引入,但是X(2.0)的依赖路径更短,就会选X(2.0)为最终依赖
-
第一声明原则
在依赖路径长度相等的前提下,在POM中的依赖声明顺寻决定了谁会被解析使用,顺序最靠前的依赖会被选择。
如:存在两个依赖关系,A->B->X(1.0)和A->C->X(2.0),此时X依赖的版本1.0和2.0同时被引入,而且两者的依赖路径长度相等,如果B的声明在C的前面,那么版本1.0被选为最终依赖。
依赖处理最佳实践
排除依赖
项目中通过传递性依赖特性隐式地引入了很多依赖,此时可能需要自己指定依赖版本,这时候就需要排除特定依赖再显式地引入特定依赖了。排除依赖通过exclusions标签实现。常见的就是在springboot中排除默认logback依赖,自己引入log4j等其他日志框架
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!-- 引入log4j日志时需去掉默认的logback -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
归类依赖
使用properties标签,定义一个依赖版本常量,通过${version}引用,达到同一类多个依赖的版本统一管理的效果
优化依赖
查询已解析依赖(最终使用的所有依赖)
#查询依赖列表
mvn dependency:list
#查询依赖树
mvn dependency:tree
#依赖分析,只会分析编译和测试需要的依赖,运行时需要的依赖无法发现
#Used undeclared dependencies found: 项目中直接import使用,隐式引入的依赖,这种依赖应该尽量使用显示声明引入
#Unused declared dependencies found: 项目中未使用,但是显示声明的依赖,但是也不能排序运行时是否使用,不能简单的删除
mvn dependency:analyze
部分内容摘录自《maven实战》




