正确设置 可避免 noclassdeffounderror,因它严格控制依赖在编译、测试、运行时的可见性:compile 全阶段参与但会传递,provided 仅编译测试期生效且不打包,runtime 不参与编译但进运行时,test 仅限测试代码。

为什么 pom.xml 里写对 <scope></scope> 能避免运行时报 NoClassDefFoundError
因为 Maven 的依赖传递和类路径(classpath)构建完全由 <scope></scope> 控制。它不是可有可无的修饰,而是决定“这个 jar 在编译、测试、运行时到底能不能被看见”的开关。
-
compile(默认):参与编译、测试、打包、运行;但会传递给下游项目 —— 如果你写的工具包引用了slf4j-api并设为compile,下游项目就得自己管实现(比如slf4j-simple),否则启动就炸 -
provided:只在编译和测试期生效,打包时剔除 —— 适合servlet-api这类由容器(Tomcat)提供的依赖,写成compile会导致本地跑得通、部署到 Tomcat 后因版本冲突而LinkageError -
runtime:不参与编译,但进包、进运行时 —— 典型如mysql-connector-java,接口在 JDK 里(java.sql.*),实现才需要加载 -
test:仅限src/test/java,打出来的jar里根本不会包含它
执行 mvn package 时没生成可执行 jar?检查 maven-jar-plugin 和 maven-shade-plugin 的分工
maven-jar-plugin 只负责把 src/main/classes 打成普通 jar;想一键运行,必须用 maven-shade-plugin 把所有依赖“揉”进去,并指定入口类。
- 别在
<plugins></plugins>里漏掉<configuration></configuration>中的<mainclass></mainclass>—— 缺了它,java -jar xxx.jar会报no main manifest attribute - 如果项目用了 Spring Boot,直接用
spring-boot-maven-plugin,它内部已封装好 shade 逻辑;混用maven-shade-plugin可能导致META-INF/spring.*覆盖丢失,启动失败 - shade 插件默认会合并同名资源(如
META-INF/MANIFEST.MF),遇到Invalid signature file digest错误,加<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer"><resource>META-INF/*.SF</resource></transformer>
mvn clean compile 成功但 mvn test 报 ClassNotFoundException?重点查 test 依赖和 surefire 版本
测试类路径 ≠ 主代码类路径。Maven 默认用 maven-surefire-plugin 执行测试,它的 classpath 构建规则独立于主流程,且老版本(2.12 之前)不自动包含 test scope 依赖的传递依赖。
- 确认
test依赖是否显式声明 —— 比如junit-jupiter必须带<scope>test</scope>,否则src/test/java里 import 都过不了 - 升级
maven-surefire-plugin到 2.22.2+,否则像mockito-core这种通过test传递进来的依赖,在测试运行时可能根本不在 classpath 上 - 如果用了 JUnit 5,必须额外加
junit-platform-surefire-provider(旧版)或直接用surefire2.22.2+ 内置支持 —— 否则mvn test会静默跳过所有测试
多模块项目里子模块依赖父模块,为什么 mvn install 后还是报找不到 xxx:jar:1.0-SNAPSHOT
因为 Maven 默认只从本地仓库(~/.m2/repository)解析 SNAPSHOT 依赖,而 mvn compile 不触发安装,子模块无法“看到”父模块刚编译出的 class —— 它不是缓存问题,是生命周期阶段没走完。
- 开发时别只跑
mvn compile,改完父模块后至少执行mvn install(把 jar 安装进本地仓库),子模块才能拉到 - 更高效的做法是用
mvn compile -pl :child-module -am:强制先编译父模块(-am),再编译子模块(-pl),跳过 install 步骤 - CI 环境中若用
mvn deploy推送到远程仓库,注意 Nexus/Artifactory 对 SNAPSHOT 的时间戳快照策略 —— 本地mvn clean install后立刻mvn test可能仍读到旧快照,需加-U强制更新
<scope></scope> 或少一个 -U,就可能让 build 表面成功、运行崩溃。Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











