maven依赖scope控制依赖在编译、测试、运行阶段的可用性及打包行为:compile默认全阶段参与并传递;test仅限测试且不打包;provided编译测试需、运行由环境提供且不打包;runtime编译无需、运行必需且参与打包。

Maven 通过 scope 属性控制依赖在不同构建阶段的参与程度,核心是让依赖只在真正需要的时候生效,避免冗余打包、类冲突或编译失败。四个常用范围的作用不是“能不能用”,而是“什么时候能用、要不要打包、会不会传给下游”。
compile:默认且最宽泛,主代码离不开它
不写 <scope></scope> 就是 compile。它参与编译、测试、运行全过程,也会被打包进最终产物(如 JAR/WAR),还会传递给依赖你的项目。
- 适合业务逻辑强依赖的库,比如
spring-core、log4j、gson - 如果某个类在
src/main/java里 import 并调用,基本都得用 compile - 注意:过度使用 compile 容易导致 WAR 包臃肿,或与容器已有类冲突(比如重复引入 servlet-api)
test:仅限测试代码,打包时彻底剔除
只出现在 src/test/java 的编译和运行期,不会进入主程序类路径,也不会打进最终包,更不会传递出去。
- 典型代表是
junit、mockito-core、assertj - 即使你在测试里用了某个工具类,只要它没被主代码引用,就该设为 test
- 误设成 compile 会导致生产环境多带一堆测试框架,增加启动时间和安全风险
provided:编译测试要,运行时不打包
它在编译和测试阶段可用,但 Maven 明确跳过打包环节——因为运行时由外部环境(如 Tomcat、JDK、云平台)提供同名类。
- 常见于 Web 开发:servlet-api、jsp-api、jakarta.servlet-api
- 也用于 JDK 自带但需编译支持的类,比如
javax.annotation(Java 8+ 中部分注解已移入 JDK) - 关键好处:避免与服务器自带版本冲突,减小 WAR 包体积,防止 NoClassDefFoundError 或 ClassCastException
runtime:编译不用,运行必须有
源码里不 import 它的类,所以编译阶段完全不需要;但它提供的实现类会在运行时被反射或 SPI 加载,因此必须出现在运行类路径中。
- 最典型的是 JDBC 驱动:
mysql-connector-java、postgresql - 还有序列化框架的实现,比如
xstream的某些插件,或日志门面的绑定器(slf4j-log4j12) - 如果误设为 compile,虽然也能跑,但会把本不该编译依赖的实现提前暴露,可能引发意外链接或版本干扰
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











