<project> ... <dependencies> ... <dependency> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version> <type>...</type> <scope>...</scope> <optional>...</optional> <exclusions> <exclusion> ... </exclusion> ... </exclusions> </dependency> ... </dependencies> ... <project>
首先需要知道maven有三套classpath,编译classpath、测试classpath和运行classpath。
使用不同的依赖范围scope,可将依赖放入不同的classpath,即会在不同的生命周期或阶段生效。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> </parent> <!-- 由于一个项目只能有一个父工程,所以可通过此方式继承其他工程的依赖版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
依赖范围与classpath的关系
如果A依赖于B,B依赖于C,我们说A对B是第一直接依赖,B对C是第二直接依赖,A对C是传递性依赖。传递性依赖和第一直接依赖范围、第二直接依赖范围有关。
最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,则传递性依赖情况如下:
为方便记忆,总结如下:
maven具有依赖调解机制,当碰到如这样的依赖关系:A -> B -> C -> X(1.0)、A -> D -> X(2.0),X是A的传递性依赖,maven会根据某些原则自主决定X的依赖版本,最终X的依赖版本只会有一个。
实际开发中,建议显式指明或排除相同依赖的版本,不应该依赖于maven的依赖调解机制。
通过optional标签指定,默认为false,即满足依赖传递的条件时,此依赖会被传递,显式指定为true时,此依赖不会被传递。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
由于某种原因,不想引入某个传递性依赖时,或发生依赖冲突时(即同一个groupId和artifactId存在不同的version时,不应依赖自动调解),可通过exclusions排除一个或多个传递性依赖。
声明exclusion时只需要groupId和artifactId,因为maven解析后的依赖中,groupId和artifactId不会重复。
当需要依赖同一个工程的不同模块时,这些依赖的版本往往是相同的,此时可通过maven属性将版本号归类,达到避免重复、防止版本冲突、方便版本升级的目的。
如很多对Spring Framework的依赖,可统一管理版本:
<properties> <spring.version>4.1.3.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> </dependencies>
经过maven的依赖传递机制和依赖调解,以及显式声明和排除依赖后,最终得到的那些依赖叫已解析依赖。可通过以下命令查看和优化已解析依赖:
mvn dependency:list #查看已解析依赖
mvn dependency:tree #查看依赖树,了解依赖传递信息 #注意依赖树中显示的依赖范围表示对当前工程的依赖范围
mvn dependency:analyze #分析依赖树 #Used undeclared dependencies表示使用未显式声明的依赖 #Unused declared dependencies表示未使用的显式声明的依赖 #此命令只会分析编译主代码和测试代码需要用到的依赖,不分析运行测试代码和主代码的依赖,也就是说无法分析runtime依赖范围的依赖
参考:《Maven实战》
原文:https://www.cnblogs.com/xiaohang123/p/15181810.html