报错急救台
贴上报错就动手:55 条真实特征,每条只回答三件事——为什么会这样、第一步做什么、该回哪篇教程
mvn 不是内部或外部命令终端找不到 mvn
Maven 的 bin 目录不在 PATH 里,或只装了 IDEA 内置的 Maven。
怎么修:把 <maven>/bin 加进 PATH,或直接用 mvnw(项目自带的 wrapper)。验证:mvn -v 能输出版本号。
相关教程 →JAVA_HOME not definedJAVA_HOME 没设或指错
JAVA_HOME 必须指向 JDK 根目录,指到 bin 或 jre 都会让工具链找不到 tools。
怎么修:export JAVA_HOME=JDK 根目录(不含 bin),Windows 改系统变量后重开终端,用 java -version 验证。
相关教程 →Unsupported class file major version字节码版本比运行的 JVM 新
class 文件用更高版本 JDK 编译(如 61=17),却跑在更低版本 JVM 上(major 55=11)。
怎么修:统一版本:要么把运行 JDK 升上去,要么在 pom 里把 <java.version> 降到目标版本,重新打包。
相关教程 →cannot find symbol编译期找不到类或包
绝大多数是 import 缺失/包名拼错/依赖没下载,少数是源码目录没被标成 Sources Root。
怎么修:先看报错第一行的类名,再确认 pom 里有对应依赖、mvn -U 刷新、IDEA 里 Mark Directory as Sources Root。
相关教程 →Could not resolve dependencies依赖下不来
仓库里没有这个坐标:groupId/artifactId/version 写错、镜像源没同步、或私库没配 settings.xml。
怎么修:去 mvnrepository 核对三坐标是否真的存在,删掉 ~/.m2 里那个 _remote.repositories 失败的目录再 mvn -U;公司私库要配 mirror 与 server 凭证。
相关教程 →duplicate class同一个类出现在两个 jar 里
依赖树里有两组坐标打包了同样的类(典型:javax.* 与 jakarta.*、或 commons-logging 被引了两次)。
怎么修:mvn dependency:tree -Dverbose 找重复,用 <exclusions> 只留一组,别用「谁先加载算谁」的运气。
相关教程 →NoSuchBeanDefinitionException容器里没有这个 Bean
类没被扫到(不在启动类包路径下 / 忘了 @Service)、@Qualifier 名字写错,或者那个 Bean 的条件装配没通过。
怎么修:先读 message 里缺的类型全名,确认包在扫描范围内;再用启动日志的条件评估报告或 /actuator/beans 看它到底有没有被装配。
相关教程 →BeanCurrentlyInCreationException循环依赖(且没能被三级缓存解开)
构造器注入的互相引用、或 prototype Bean 互引,都超出单例三级缓存能处理的范围;Boot 2.6+ 默认还直接禁止循环引用。
怎么修:优先重构掉环(抽第三方、改事件);确实要留就把其中一个改成 setter/@Lazy 注入,或显式 spring.main.allow-circular-references=true ——这是止痛药不是治病。
相关教程 →NoUniqueBeanDefinitionException同一类型有多个候选 Bean
接口有两个实现都在容器里,注入点没说明要哪个。
怎么修:在注入点加 @Qualifier("beanName"),或给主实现标 @Primary;如果用 @ConditionalOnMissingBean 做自动配置,检查条件顺序。
相关教程 →BeanCreationExceptionBean 创建失败(最外层包装异常)
这行本身不告诉你根因,真正原因在往下第三个 Caused by:构造器抛了、@PostConstruct 抛了、或属性绑定失败。
怎么修:从下往上读日志,找最后一个 Caused by;那里才是要修的地方,改完最外层的错误自然消失。
相关教程 →Could not resolve placeholder${} 占位符没配上值
配置里没有这个键,且占位符没写默认值;也可能是 profile 没激活导致那份文件根本没被读。
怎么修:要么补配置,要么写默认值 ${server.port:8080};确认当前激活的 profile(启动日志第一行有 The following N profiles are active)。
相关教程 →java.lang.ClassCastException: com.sun.proxy代理类型和注入类型不匹配
JDK 动态代理只实现接口,你却按实现类去注入;或 proxyTargetClass=true 与字段类型对不上。
怎么修:注入点改成接口类型(推荐),或 spring.aop.proxy-target-class=true 让它走 CGLIB 子类代理。
相关教程 →aspect is not applied切面写了但没执行
切点表达式没匹配上(execution 的返回类型/包名/参数写法严格),或者目标 Bean 压根没被代理(自己调自己的自调用)。
怎么修:用 execution(* com.example..service.*.*(..)) 这种宽松写法先验证能不能命中,再收紧;自调用问题看第 12 篇。
相关教程 →Port 8080 was already in use端口被占用
8080 上有别的进程(常见是上一次没关干净的 java,或 Tomcat/Nginx)。
怎么修:启动日志会直接告诉你 PID:Windows 用 netstat -ano | findstr 8080 再 taskkill /pid,macOS/Linux 用 lsof -i:8080;或临时 --server.port=8081。
相关教程 →Failed to configure a DataSource引了 jdbc starter 却没给数据源配置
自动配置发现有 DataSource 需求,但 spring.datasource.url 缺失且类路径上没有内嵌库,于是直接拒绝启动。
怎么修:补 spring.datasource.url/username/password 与驱动依赖;不想连库就在启动类排除 DataSourceAutoConfiguration。
相关教程 →APPLICATION FAILED TO START启动直接失败并打印诊断报告
Boot 的失败分析器把根因写在这块横幅里,通常是缺 Bean、环、或端口冲突;横幅之下才是原始堆栈。
怎么修:只读 APPLICATION FAILED TO START 这一段(它已经告诉你该改哪里),再看 Description 下的 Action;不要一上来翻几百行堆栈。
相关教程 →while scanning a simple keyyml 缩进或写法不合法
YAML 用空格缩进表达层级:出现 Tab、冒号后没空格、同一行混用两种缩进,都会在这里炸。
怎么修:全部改回 2 空格、冒号后必须空格、值里有冒号时用引号包住(如 url: "jdbc:mysql://...")。
相关教程 →HttpMessageNotReadableException@RequestBody 没收到能解析的 JSON
客户端没发 body、Content-Type 不是 application/json、或 JSON 字段与 Java 类型不匹配(多/少字段、数字写成字符串)。
怎么修:确认请求头带 Content-Type: application/json;字段对不上就先看异常里的原字段名,再用 @JsonIgnoreProperties 或补 DTO。
相关教程 →MethodArgumentNotValidException参数校验没过,400 里全是 fieldErrors
@Valid 生效了但请求体不满足约束——这其实是好事,说明脏数据没进业务层。
怎么修:响应体里 objectName/fieldErrors 给出字段与消息;给 @ExceptionHandler(MethodArgumentNotValidException.class) 统一转成「字段+中文提示」再返回。
相关教程 →Failed to convert value of type路径/查询参数类型转换失败
URL 里带进来的永远是 String,声明成 Long/LocalDate 时没有对应转换器或格式不对(如 2024/01/05 对 yyyy-MM-dd)。
怎么修:日期用 @DateTimeFormat(iso = DATE),数字声明成包装类型并加校验;全局格式用 Converter/ConverterFactory 注册。
相关教程 →Request method 'POST' is not supported405:方法和注解不一致
映射写了 @GetMapping,客户端发的是 POST(或者 @RequestMapping 没写 method,被默认放行全部方法)。
怎么修:对齐动词:前端改方法或后端换 @PostMapping;排查时先看启动日志的映射表(RequestMappingHandlerMapping)。
相关教程 →HttpMediaTypeNotAcceptableException406:客户端要的媒体类型服务端给不出
Accept 头与实际产出转换器不匹配,常见于返回了对象但类路径没有 JSON 转换器,或后缀协商把 .pdf 当扩展名。
怎么修:显式 produces = application/json,确认引了 spring-boot-starter-web(含 Jackson);扩展名协商在 Boot 3 默认关闭。
相关教程 →MissingServletRequestParameterException必填参数没传
@RequestParam 默认 required=true,名字写错或前端只发在 body 里都会命中。
怎么修:要么前端补参数,要么写 @RequestParam(name="kw", required=false, defaultValue="") 明确可选。
相关教程 →Invalid CORS request跨域被拦
浏览器发了 OPTIONS 预检,但服务端没有返回匹配的 Access-Control-Allow-* 头;很多「接口 403」其实是预检失败,请求根本没进方法。
怎么修:用 @CrossOrigin 或全局 CorsConfigurationSource(注意 allowCredentials 与 allowedOrigins=* 不能共存),并放行 OPTIONS。
相关教程 →SQLSyntaxErrorExceptionSQL 本身有问题
表名/列名拼错、关键字当标识符、或占位符写法不对(JDBC 只认 ?,不认 :name)。
怎么修:把日志里那条完整 SQL 拷进数据库客户端跑一遍——最快最诚实的排查方式。
相关教程 →DataIntegrityViolationException数据库拒绝写入(约束层面)
唯一键冲突、非空列为 null、外键指向不存在的行。Spring 已经把厂商异常翻译过了,看异常子类就能定位类别。
怎么修:唯一冲突用 upsert/先查再改;非空先补参数校验(别让脏数据走到 DAO);外键顺序是先父后子。
相关教程 →EmptyResultDataAccessExceptionqueryForObject 没查到 / 查到多行
queryForObject 的契约是「恰好一行」:0 行抛 EmptyResult,多于一行抛 IncorrectResultSize。
怎么修:可能没有就改用 query() 或 queryOptional 风格自己判空;可能多条说明查询条件不唯一,补条件或改成列表。
相关教程 →Connection is not available, request timed out after借不到连接(池子排队超时)
池被占满:长事务没提交、慢 SQL、或者开了事务却在外层又调了别的数据源;默认 30s 等待后就抛这个。
怎么修:先查有没有 @Transactional 里做远程调用/循环;把 leakDetectionThreshold=60000 打开,让 Hikari 直接告诉你连接被谁借走了。
相关教程 →CommunicationsException: Communications link failure连接被服务端单方面切断
池里的连接活得比 MySQL 的 wait_timeout 长,拿出一条已经死掉的连接;也可能是网络中断或 SSL 配置冲突。
怎么修:让 max-lifetime 明显小于 wait_timeout(如 1740000 对 28800),必要时开 keepaliveTime;别用测试环境超时值上线。
相关教程 →Invalid bound statement (not found)Mapper 接口找不到对应 SQL
namespace 与接口全限定名不一致、方法名和 statement id 不一致、或者 XML 没被打包进 classpath(Maven 默认不复制 src/main/java 下的 xml)。
怎么修:先确认 target/classes 里有那个 XML;再逐字对 namespace 与方法名;build 配置里补 resources 目录的包含规则。
相关教程 →LazyInitializationException出了会话还想懒加载
Session/持久化上下文已关闭,此时访问未加载的关联集合只能报错。常见于把实体直接返回到 Controller 层、或者 open-in-view 关了以后在 Service 外访问。
怎么修:要么在事务内用 fetch join/@EntityGraph 一次取够,要么转 DTO;spring.jpa.open-in-view=never 是更诚实的默认值。
相关教程 →Schema-validation: missing columnddl-auto=validate 发现实体与库对不上
实体写了新字段但库里没这一列(或列名映射不同)。validate 不会改库,只会告诉你差在哪。
怎么修:用 Flyway/Liquibase 补一条迁移脚本再启动;把 validate 改成 none,永远不要靠 update 在生产改表。
相关教程 →ObjectOptimisticLockingFailureException乐观锁冲突:两个人同时改了同一行
@Version 字段与库里不一致——另一个事务已经提交过。这是数据没被覆盖的证据,不是 bug。
怎么修:业务层重读→合并→重试(或返回「请刷新」给用户)。别用 @Version 去掉来「解决」报错。
相关教程 →Transactional 不生效@Transactional 没起作用
最常见的三种:同类自调用绕过代理、方法不是 public、异常是被 catch 吞掉的受检异常(默认只回滚 RuntimeException)。
怎么修:自调用改成注入自己或拆类;异常用 rollbackFor = Exception.class 明确声明;别让 try/catch 把异常吃掉还不重抛。
相关教程 →No qualifying bean of type找不到事务管理器
类路径没有任何能自动配出事务管理器的技术(既没 jdbc/jpa 也没手写 @Bean),或者引了多个数据源却没有 @Primary 的那个。
怎么修:确认 starter 在;多数据源时给主事务管理器加 @Primary,或显式声明 @Bean DataSourceTransactionManager。
相关教程 →@Cacheable 没有缓存效果加了 @Cacheable 却还是每次查库
要么没开 @EnableCaching / 没配 CacheManager,要么自调用绕过代理,要么 key 每次都不同(默认用参数,传了 new Date())。
怎么修:启动日志确认 CacheManager 类型;把方法拆到另一个 Bean;用 @Cacheable(key = "#id") 固定 key,并用 SimpleCacheManager 的 sync/允许 null 配置。
相关教程 →RedisConnectionException: Unable to connect连不上 Redis
地址/端口/密码错,或者 Redis 只绑了 127.0.0.1、开了 protected-mode 却没设 bind;云上还常见安全组没放行 6379。
怎么修:先用 redis-cli -h <host> -p 6379 -a <pwd> ping 打通,再回到应用配置;注意 Boot 3 的属性前缀是 spring.data.redis.*。
相关教程 →SerializationException缓存值序列化失败
默认 Jackson 序列化要求对象有无参构造、字段可读、不持有 LocalDateTime/内部类等它处理不了的东西;缓存值还必须是不可变语义。
怎么修:换 GenericJackson2JsonRedisSerializer 并注册 JavaTimeModule,或存进缓存前转成专门的 DTO。
相关教程 →Failed to load ApplicationContext集成测试连容器都没起来
测试用的配置缺了主配置有的东西(数据源、profile、某个 Bean 的条件),或 @MockBean 换成 @MockitoBean 后 Boot 3.4 起写法不同。
怎么修:看这个异常下面第一个 Caused by——它和被测系统启动失败是同一条路径;测试资源里补 application-test.yml 与 @ActiveProfiles。
相关教程 →UnnecessaryStubbingExceptionMockito 的打桩与真实调用对不上
要么打桩的方法根本没被调用(代码改了/分支变了),要么实参与打桩不一致(Mockito 默认严格匹配),要么 verify 的交互次数没写对。
怎么修:先怀疑业务代码路径变了;用 lenient() 只该用在公共 @BeforeEach 里,别拿它当止痛药;实参用 anyX() 前先确认语义。
相关教程 →SLF4J: Failed to load class日志门面绑定冲突
类路径上有两套以上实现(logback 与 log4j-to-slf4j、或 spring-boot-starter-logging 与别人引的 starter-log4j2 同时存在)。
怎么修:只用一个:mvn dependency:tree 找出多余实现,用 starter 排除机制剔除,再确认没有自己引 slf4j-simple。
相关教程 →没有日志输出写了日志却什么都不打印
级别高于配置(root=INFO 时 DEBUG 被丢)、Logger 名和包名不一致导致级别没落到那个 logger、或者 logback.xml 写错把 appender 关了。
怎么修:临时设 logging.level.<你的包>=DEBUG 验证;确认 LoggerFactory.getLogger(YourClass.class) 的类全名在配置里对得上。
相关教程 →no main manifest attribute打出来的 jar 不能 java -jar
没用 spring-boot-maven-plugin 重新打包(repackage),得到的是普通 jar:MANIFEST.MF 里没有 Main-Class 与 BOOT-INF 结构。
怎么修:在 build/plugins 里加 spring-boot-maven-plugin;确认它执行在 package 阶段;java -jar 再试。
相关教程 →ClassNotFoundException运行时找不到类(编译期却有)
fat jar 里的 BOOT-INF/lib 没被 LaunchedClassLoader 读到(jar 被二次压缩/损坏),或依赖 scope 写成 provided/test 导致没打进包。
怎么修:jar tf 看 BOOT-INF/lib 里有没有那个 jar;确认 scope;别用普通工具再压一遍 fat jar。
相关教程 →OOMKilled进程被杀或堆溢出
容器给了限额但 JVM 看不到(写死 -Xmx 或按宿主机内存算默认堆);Metaspace 涨通常是动态类生成/代理过多。
怎么修:用 -XX:MaxRAMPercentage=75.0 让堆跟着容器配额走,别写死 -Xmx;堆真不够再查大集合与缓存,Metaspace 用 -XX:MaxMetaspaceSize 兜住。
相关教程 →'java' is not a command镜像里没有 java
基础镜像选了不含 JDK 的(如 alpine 裸镜像),或用了 jre 镜像却 ENTRYPOINT 写成了 java 的路径别名;也可能是多阶段构建忘了把 JRE 拷进最终镜像。
怎么修:换成 eclipse-temurin:17-jre(或先 COPY --from 拷入 JRE),docker run --rm image java -version 验证。
相关教程 →401 Unauthorized引了 Security 之后接口全挂
默认策略是「所有请求都要认证」,401 是没登录/凭证不对,403 是登录了但权限不够;两个是不同过滤器报的。
怎么修:先明确规则:authorizeHttpRequests 里放行你确实想公开的接口,其余再收紧;调试期打开 logging.level.org.springframework.security=TRACE 看命中了哪条。
相关教程 →Invalid CSRF tokenPOST 请求被 CSRF 拦掉
Session/表单类应用默认开启 CSRF 保护,前端没带 X-CSRF-TOKEN 头或 _csrf 参数;纯 token 的 REST API 才考虑关掉它。
怎么修:用 cookieCsrfTokenRepository + 前端回传头,或对无状态 JWT 的接口关闭 csrf();不要用关闭来「修」有会话的应用。
相关教程 →ExpiredJwtException令牌校验不过
Expired 是时间到了(或服务器时钟漂移);Signature/Malformed 是密钥不一致、令牌被截断、或把 refresh token 当 access token 用了。
怎么修:统一签发与校验的密钥与算法;给时钟留容忍(clockSkew);前端按 401 走刷新流程,并区分两类令牌。
相关教程 →RejectedExecutionException线程池把任务拒了
核心/最大线程数与队列容量都不够,触发拒绝策略。默认 AbortPolicy 直接抛,看着像「偶发失败」。
怎么修:显式配 ThreadPoolTaskExecutor(容量按下游承载力算,不要拍脑袋 1000),并给 CallerRunsPolicy 这类有代价的策略写清理由。
相关教程 →@Async 异常没被捕获异步任务里的异常「不见了」
返回 void 的 @Async 方法,异常由 AsyncUncaughtExceptionHandler 处理,默认只打一行日志,业务以为成功了。
怎么修:让方法返回 CompletableFuture 并在调用处 handle,或注册一个会告警的 AsyncUncaughtExceptionHandler。
相关教程 →TransactionalEventListener 没有触发事务事件监听器没跑
@TransactionalEventListener 只在事务阶段匹配时触发——发布点不在事务里,AFTER_COMMIT 永远不会来。
怎么修:确认发布方真的在事务内;阶段用错就改 phase;需要兜底再加普通 @EventListener 处理无事务场景。
相关教程 →not present in metadata after连上了地址但拿不到 topic 元数据
broker advertised listeners 返回的是内网地址(容器/跨机器场景最常见),客户端拿到后连不上;或 topic 没开自动创建。
怎么修:把 broker 的 advertised.listeners 配成客户端可达的地址;本地测试可设 auto.create.topics=true,生产应预先建 topic。
相关教程 →PRECONDITION_FAILED - inequivalent argRabbitMQ 声明队列时参数不一致
同名队列已存在且 durable/type/arguments 与代码声明不同——Rabbit 不允许改已存在队列的属性。
怎么修:改名或删掉旧队列;团队里把队列声明收敛到一处配置,别让两处代码用同一名字声明不同属性。
相关教程 →Whitelabel Error PageActuator 端点 404
没引 actuator starter,或者引了但该端点不在 web 暴露白名单里(默认只有 health 与 info);换了管理端口后又打错端口也长这样。
怎么修:先 curl /actuator 看索引页的 _links(它不会骗你),再补 include;注意管理端口与业务端口分别试一遍。
相关教程 →