Spring Maven插件填充BOOT-INF/lib的逻辑及相关依赖树问题咨询
问题背景
通过Spring Initializer创建的项目包含以下两个依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
执行命令 mvn dependency:tree -Dincludes=org.springframework:spring-core 时,输出显示spring-core是spring-boot-starter-test的子依赖:
org.springframework.boot:spring-boot-starter-test:jar:3.1.5:test \- org.springframework:spring-core:jar:6.0.13:compile
但实际打包后,spring-core仍被加入到可执行JAR的BOOT-INF/lib目录中。按常理,test范围依赖的子依赖应该被排除,这说明Spring Boot Maven插件使用的依赖逻辑和mvn dependency:tree不一致。
当注释掉spring-boot-starter-test依赖后,再次执行mvn dependency:tree -Dincludes=org.springframework:spring-core,输出显示spring-core属于spring-boot-starter-oauth2-resource-server的依赖链:
org.springframework.boot:spring-boot-starter-oauth2-resource-server:jar:3.1.5:compile \- org.springframework.boot:spring-boot-starter:jar:3.1.5:compile \- org.springframework:spring-core:jar:6.0.13:compile
补充信息:使用maven-dependency-plugin 3.5.0和spring-boot-maven-plugin 3.1.5,执行mvn dependency:tree -Dscope=compile时未显示spring-core依赖。
问题与解答
1. Spring Boot Maven插件为何及如何填充BOOT-INF/lib?是否使用Maven的dependency:tree还是自有逻辑?
Spring Boot Maven插件不直接依赖dependency:tree的输出,而是基于Maven原生的依赖解析机制,但会针对Spring Boot可执行JAR的打包需求做适配:
- 核心规则是:插件会收集所有compile和runtime范围的依赖(包括传递依赖),无论这些依赖最初通过哪个父依赖引入。
spring-core被纳入BOOT-INF/lib的原因是它本身的生效范围是compile——即使它被test范围的依赖引入,只要存在另一条compile/runtime路径的依赖(即spring-boot-starter-oauth2-resource-server的依赖链),Maven的依赖解析会优先保留范围更宽的(compile > runtime > test),因此spring-core的实际生效范围是compile,插件会将其纳入打包。dependency:tree仅展示了依赖被引入的其中一条路径,不代表这是唯一路径或生效范围。
2. 是否有工具可查看Spring填充BOOT-INF/lib所用的依赖树?
有几种实用方式:
- 执行Spring Boot Maven插件命令:
mvn spring-boot:build-info,生成的build-info.properties文件会包含最终打包的依赖列表(非树形结构)。 - 使用Maven依赖插件命令:
mvn dependency:list -DincludeScope=compile,runtime,可列出所有会被纳入BOOT-INF/lib的依赖;若需要树形结构,可结合-DoutputFile参数导出结果后分析,或使用Maven Dependency Analyzer插件可视化依赖关系。 - 直接解压生成的可执行JAR,查看
BOOT-INF/lib目录下的JAR文件,即为插件打包的所有依赖。
3. 能否强制dependency:tree在有选择时优先显示compile范围的依赖树?
可以通过调整命令参数实现:
- 执行
mvn dependency:tree -Dscope=compile -Dincludes=org.springframework:spring-core:指定只展示compile范围的依赖路径,即可优先看到spring-core通过compile依赖引入的链路。 - 结合
-Dverbose参数:mvn dependency:tree -Dverbose -Dincludes=org.springframework:spring-core,会展示该依赖的所有引入路径,你可从中筛选compile范围的那条。 - 若执行
mvn dependency:tree -Dscope=compile未显示spring-core,可先执行mvn clean清理缓存后再重新运行命令,排除缓存干扰。
内容的提问来源于stack exchange,提问作者Vsevolod

