java中实现全局异常捕获并写入错误日志的核心是分层拦截:web层用@controlleradvice统一处理控制器异常,非web场景(如线程池、定时任务)用thread.setdefaultuncaughtexceptionhandler兜底,再结合logback+slf4j结构化记录带堆栈的error日志,并补充监控告警。

Java 中实现全局异常捕获并写入错误日志,核心在于分层拦截:对 Web 层用 @ControllerAdvice,对非 Web 场景(如线程池、定时任务)用 Thread.setDefaultUncaughtExceptionHandler,再配合统一的日志框架(如 Logback + SLF4J)格式化记录。
Web 应用:用 @ControllerAdvice 拦截控制器异常
这是 Spring Boot 项目最常用、最优雅的方式。它能集中处理所有 @RestController 和 @Controller 抛出的未被捕获异常,支持按异常类型定制响应,同时记录结构化日志。
- 定义一个全局异常处理器类,加上
@ControllerAdvice注解 - 用
@ExceptionHandler方法分别处理Exception、IllegalArgumentException等具体类型 - 在方法体内调用
log.error("业务异常", e),SLF4J 会自动记录堆栈 - 返回统一错误响应(如
ResponseEntity或自定义ErrorResult)
示例片段:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
非 Web 场景:设置默认未捕获异常处理器
Spring 管理的 Bean(如 @Scheduled 定时任务、@Async 异步方法、手动创建的线程)若抛出未捕获异常,不会进入 @ControllerAdvice。此时需主动设置线程级兜底处理器。
- 在应用启动时(如
@PostConstruct或SpringApplicationRunListener),调用Thread.setDefaultUncaughtExceptionHandler(...) - 处理器内使用
logger.error("线程异常: {}", t.getMessage(), t)记录带堆栈的日志 - 注意:Spring 的
TaskExecutor(如ThreadPoolTaskExecutor)可配置setThreadFactory,让每个线程都带上自定义异常处理器
日志配置:确保错误堆栈可读且可追溯
光捕获不够,日志内容要实用。关键点有三个:
- 使用
%d{yyyy-MM-dd HH:mm:ss.SSS}+%X{traceId}(集成 SkyWalking 或 Logback MDC)补全上下文 - ERROR 级别日志必须传入
Throwable参数(即log.error("msg", e)),否则堆栈丢失 - 避免在 catch 块里只写
log.error(e.toString())—— 这样没有堆栈,等于没记
进阶建议:补充异常监控与告警
生产环境仅写日志不够,建议叠加轻量级可观测能力:
- 用
@EventListener监听ApplicationFailedEvent,捕获 Spring 启动失败 - 对关键业务异常(如支付失败、库存扣减异常)打标(如加
MDC.put("errorType", "PAY_FAILED")),便于 ELK 聚合分析 - 结合 Prometheus + Grafana 设置 ERROR 日志突增告警(通过日志采集器暴露指标)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










