正确配置<scope>可避免NoClassDefFoundError等运行时错误:compile全阶段生效且传递;provided仅编译测试可用、不打包不传递;runtime编译不可用但测试运行必需且打包传递;test仅限测试代码。

pom.xml 中配置依赖范围(scope),只需在 <dependency> 块内添加 <scope> 元素,并设为对应值即可。关键不是“能不能配”,而是“为什么这么配”——它直接影响编译是否通过、打包是否臃肿、运行是否报错。
provided:编译测试需要,运行时由环境提供
典型场景是 Servlet API、JSP API 等——你写 Web 应用要引用 javax.servlet-api 才能编译通过,但部署到 Tomcat 或 Jetty 时,容器已自带该类库。重复打包会导致冲突或 ClassLoader 异常。
配置示例:
<dependency><br> <groupId>javax.servlet</groupId><br> <artifactId>javax.servlet-api</artifactId><br> <version>4.0.1</version><br> <scope>provided</scope><br> </dependency>
效果:
• 编译主代码和测试代码时可用
• 不会打入最终的 WAR/JAR 包
• 不会传递给依赖你项目的其他模块(即不会影响下游项目)
runtime:编译不需要,运行和测试才需要
典型例子是 JDBC 驱动。主代码里只用 JDK 自带的 java.sql.* 接口(编译期就够了),真正加载 MySQL 或 PostgreSQL 驱动是在运行时(比如 Spring Boot 启动连接池时)或执行数据库测试时才需要实现类。
配置示例:
<dependency><br> <groupId>mysql</groupId><br> <artifactId>mysql-connector-java</artifactId><br> <version>8.0.33</version><br> <scope>runtime</scope><br> </dependency>
效果:
• 编译主代码时完全不参与(不会出现在编译 classpath)
• 测试和运行阶段必须存在(会打入最终包)
• 会被传递给下游项目(除非被显式排除)
对比要点:别只看“打不打包”,要看“在哪生效”
compile(默认):全阶段有效,打包、传递、编译、测试、运行都用得上。
provided:仅编译 + 测试 classpath 有,不打包、不传递。
runtime:编译 classpath 没它,测试/运行 classpath 有,会打包、会传递。
test:只在 src/test/ 下生效,不打包、不传递。
常见误配:
• 把 mysql-connector-java 设成 provided → 运行时报 ClassNotFoundException: com.mysql.cj.jdbc.Driver
• 把 servlet-api 设成 compile → WAR 包里多出一个 servlet-api.jar,Tomcat 启动可能因版本不一致抛 LinkageError


















