问题描述
Maven中的依赖<scope>provided</scope>
和<optional>true</optional>
是否会打包到最终的jar包中?
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
<optional>true</optional>
</dependency>
先说结论:
1、如果是pringboot的打包插件,即使你设置了以上两个属性这两个依赖依然会被打包到可执行jar包中。这是SpringBoot的机制,具体看下文分析。
2、如果是普通原生的maven打包上面两者是不会打包到jar文件中的。
现象分析
探讨分析Spring Boot打包时<scope>provided</scope>
和<optional>true</optional>
的行为,两者是否需要被打打包到可执行jar包的BOOT-INFO/lib目录下?
现在让我分析打包后的jar文件,看看实际包含的依赖情况:
cd /Users/shouzhi/nvxclouds/project/springboot-x-example && jar -tf target/springboot-x-example-1.0.0.jar | grep -E "(commons-lang3|commons-beanutils)" | head -10
输出输出>>>>>>
<ep -E "(commons-lang3|commons-beanutils)" | head -10
BOOT-INF/lib/commons-lang3-3.12.0.jar
BOOT-INF/lib/commons-beanutils-1.9.4.jar
现在分析一下Maven的依赖树,看看这些依赖是如何被引入的:
mvn dependency:tree | grep -A 5 -B 5 -E "(commons-lang3|commons-beanutils)"
输出>>>>>>
Downloading from nexus: http://192.168.50.16:8081/repository/maven-public/com/nvxclouds/baize/tally/tally-co
mmon-s3/3.2.0-springboot2-jdk8-SNAPSHOT/maven-metadata.xml
Downloaded from nexus: http://192.168.50.16:8081/repository/maven-public/com/nvxclouds/baize/tally/tally-com
mon-s3/3.2.0-springboot2-jdk8-SNAPSHOT/maven-metadata.xml (841 B at 49 kB/s)
[INFO]
[INFO] --- dependency:3.3.0:tree (default-cli) @ springboot-x-example ---
[INFO] com.shouzhi.test:springboot-x-example:jar:1.0.0
[INFO] +- org.apache.commons:commons-lang3:jar:3.12.0:provided
[INFO] +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
[INFO] | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | \- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.18:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.7.18:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.7.18:compile
查看完整的依赖树来全面分析:
mvn dependency:tree
输出>>>>>>
......
Downloaded from nexus: http://192.168.50.16:8081/repository/maven-public/com/nvxclouds/baize/tally/tally-com
mon-s3/3.2.0-springboot2-jdk8-SNAPSHOT/maven-metadata.xml (841 B at 44 kB/s)
[INFO]
[INFO] --- dependency:3.3.0:tree (default-cli) @ springboot-x-example ---
[INFO] com.shouzhi.test:springboot-x-example:jar:1.0.0
[INFO] +- org.apache.commons:commons-lang3:jar:3.12.0:provided
[INFO] +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
[INFO] | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | \- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.18:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.7.18:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.7.18:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.18:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:2.7.18:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.2.12:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.2.12:compile
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.17.2:compile
[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.17.2:compile
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:1.7.36:compile
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.30:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:2.7.18:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.5:compile
[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.13.5:compile
[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.13.5:compile
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.13.5:compile
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.13.5:compile
[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.13.5:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.7.18:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.83:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.83:compile
[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.83:compile
[INFO] | +- org.springframework:spring-web:jar:5.3.31:compile
[INFO] | | \- org.springframework:spring-beans:jar:5.3.31:compile
[INFO] | \- org.springframework:spring-webmvc:jar:5.3.31:compile
[INFO] | +- org.springframework:spring-aop:jar:5.3.31:compile
[INFO] | +- org.springframework:spring-context:jar:5.3.31:compile
[INFO] | \- org.springframework:spring-expression:jar:5.3.31:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:2.7.18:test
[INFO] | +- org.springframework.boot:spring-boot-test:jar:2.7.18:test
[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.7.18:test
[INFO] | +- com.jayway.jsonpath:json-path:jar:2.7.0:test
[INFO] | | +- net.minidev:json-smart:jar:2.4.11:test
[INFO] | | | \- net.minidev:accessors-smart:jar:2.4.11:test
[INFO] | | | \- org.ow2.asm:asm:jar:9.3:test
[INFO] | | \- org.slf4j:slf4j-api:jar:1.7.36:compile
[INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.3:test
[INFO] | | \- jakarta.activation:jakarta.activation-api:jar:1.2.2:test
[INFO] | +- org.assertj:assertj-core:jar:3.22.0:test
[INFO] | +- org.hamcrest:hamcrest:jar:2.2:test
[INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.8.2:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.8.2:test
[INFO] | | | +- org.opentest4j:opentest4j:jar:1.2.0:test
[INFO] | | | +- org.junit.platform:junit-platform-commons:jar:1.8.2:test
[INFO] | | | \- org.apiguardian:apiguardian-api:jar:1.1.2:test
[INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.8.2:test
[INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.8.2:test
[INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.8.2:test
[INFO] | +- org.mockito:mockito-core:jar:4.5.1:test
[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.12.23:test
[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.12.23:test
[INFO] | | \- org.objenesis:objenesis:jar:3.2:test
[INFO] | +- org.mockito:mockito-junit-jupiter:jar:4.5.1:test
[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.1:test
[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] | +- org.springframework:spring-core:jar:5.3.31:compile
[INFO] | | \- org.springframework:spring-jcl:jar:5.3.31:compile
[INFO] | +- org.springframework:spring-test:jar:5.3.31:test
[INFO] | \- org.xmlunit:xmlunit-core:jar:2.9.1:test
[INFO] +- com.alibaba.fastjson2:fastjson2:jar:2.0.55:compile
[INFO] +- org.projectlombok:lombok:jar:1.18.30:compile
[INFO] +- com.nvxclouds.baize.tally:tally-common-tidb:jar:3.2.0-springboot2-jdk8-SNAPSHOT:compile
[INFO] | +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] | +- com.mysql:mysql-connector-j:jar:8.0.33:compile
[INFO] | \- com.zaxxer:HikariCP:jar:4.0.3:compile
[INFO] \- com.nvxclouds.baize.tally:tally-common-s3:jar:3.2.0-springboot2-jdk8-SNAPSHOT:compile
[INFO] \- com.amazonaws:aws-java-sdk-s3:jar:1.11.343:compile
[INFO] +- com.amazonaws:aws-java-sdk-kms:jar:1.11.343:compile
[INFO] +- com.amazonaws:aws-java-sdk-core:jar:1.11.343:compile
[INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.14:compile
[INFO] | | +- org.apache.httpcomponents:httpcore:jar:4.4.16:compile
[INFO] | | \- commons-codec:commons-codec:jar:1.15:compile
[INFO] | +- com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:jar:2.13.5:compile
[INFO] | \- joda-time:joda-time:jar:2.8.1:compile
[INFO] \- com.amazonaws:jmespath-java:jar:1.11.343:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.997 s
[INFO] Finished at: 2025-09-03T08:35:30+08:00
[INFO] ------------------------------------------------------------------------
现在分析一下为什么会出现这种情况。首先让我检查一下是否有其他传递依赖引入了这些包:
mvn dependency:tree -Dincludes=org.apache.commons:commons-lang3
输出>>>>>>
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< com.shouzhi.test:springboot-x-example >----------------
[INFO] Building tidb-test 1.0.0
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
。。。。。。。
Downloaded from nexus: http://192.168.50.16:8081/repository/maven-public/com/nvxclouds/baize/tally/tally-com
mon-s3/3.2.0-springboot2-jdk8-SNAPSHOT/maven-metadata.xml (841 B at 44 kB/s)
[INFO]
[INFO] --- dependency:3.3.0:tree (default-cli) @ springboot-x-example ---
[INFO] com.shouzhi.test:springboot-x-example:jar:1.0.0
[INFO] \- org.apache.commons:commons-lang3:jar:3.12.0:provided
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.902 s
[INFO] Finished at: 2025-09-03T08:35:41+08:00
[INFO] ------------------------------------------------------------------------
mvn dependency:tree -Dincludes=commons-beanutils:commons-beanutils
输出>>>>>>
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< com.shouzhi.test:springboot-x-example >----------------
[INFO] Building tidb-test 1.0.0
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
。。。。。。
Downloaded from nexus: http://192.168.50.16:8081/repository/maven-public/com/nvxclouds/baize/tally/tally-com
mon-s3/3.2.0-springboot2-jdk8-SNAPSHOT/maven-metadata.xml (841 B at 44 kB/s)
[INFO]
[INFO] --- dependency:3.3.0:tree (default-cli) @ springboot-x-example ---
[INFO] com.shouzhi.test:springboot-x-example:jar:1.0.0
[INFO] \- commons-beanutils:commons-beanutils:jar:1.9.4:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.921 s
[INFO] Finished at: 2025-09-03T08:35:45+08:00
[INFO] ------------------------------------------------------------------------
现在查看具体的Spring Boot Maven Plugin配置,看看是否有特殊设置:
mvn help:effective-pom | grep -A 20 -B 5 "spring-boot-maven-plugin"
输出>>>>>>
shouzhi@192 springboot-x-example % mvn help:effective-pom | grep -A 20 -B 5 "spring-boot-maven-plugin"
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
</dependency>
</dependencies>
<configuration>
<!--这个属性导致以上2个包仍然被导报到/lib中-->
<keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
--
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</execution>
</executions>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.10.0</version>
--
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</execution>
</executions>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.2.0</version>
<executions>
shouzhi@192 springboot-x-example %
现在发现了关键问题!从有效POM中可以看到一个关键配置:<keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
。
问题分析
以上现象是正确的,这是 Spring Boot Maven Plugin 的默认行为,而不是bug。
根本原因
Spring Boot 的"Fat JAR"策略
- Spring Boot 创建的是自包含的可执行JAR(Fat JAR/Uber JAR)
- 为了确保应用可以独立运行,它会默认包含所有依赖,包括
provided
和optional
的依赖
Spring Boot Maven Plugin 的默认配置
- 从有效POM可以看到:
<keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
- 这个配置导致
provided
依赖也被打包进去
- 从有效POM可以看到:
传统Maven vs Spring Boot的区别:
<!-- 传统Maven:provided依赖不会被打包 --> <scope>provided</scope> <!-- Spring Boot:默认仍会打包,确保独立运行 -->
验证结果解释
commons-lang3
(provided) → 被打包:因为keepDependenciesWithProvidedScope=true
commons-beanutils
(optional) → 被打包:optional主要影响传递依赖,当前项目中仍会被打包
如何控制打包行为
如果您确实不想让这些依赖被打包,可以在 spring-boot-maven-plugin
中显式排除:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclude>
<exclude>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
总结
验证结果是完全正确的!Spring Boot 的这种设计是有意为之,目的是创建一个完全自包含的可执行应用程序,即使依赖标记为 provided
或 optional
,默认情况下仍会被包含以确保应用的完整性和可移植性。