java中非受检异常需通过uncaughtexceptionhandler统一拦截并异步通知,结合钉钉/邮件告警、mdc上下文、限流降级与动态开关实现高可用可观测告警。

Java中非受检异常(RuntimeException及其子类)默认不会强制捕获,因此容易在运行时静默崩溃或影响业务逻辑。要实现在其发生时自动发送钉钉或邮件告警,核心思路是:**统一拦截未处理的异常,提取关键信息,并异步触发通知**。
全局异常拦截:使用UncaughtExceptionHandler
每个线程都可设置一个未捕获异常处理器,主线程和自定义线程均适用。这是捕获非受检异常最底层、最可靠的方式:
- 对主线程:在main方法开头调用Thread.setDefaultUncaughtExceptionHandler(...)
- 对线程池:继承ThreadPoolExecutor并重写afterExecute,或使用ThreadFactory为每个线程设置专属handler
- Handler中可获取异常类型、堆栈、线程名、时间戳等,是告警数据的基础来源
告警通道封装:钉钉机器人 + 邮件工具类
避免硬编码,将通知能力抽象为独立服务:
- 钉钉:调用其Webhook接口(需开启机器人安全设置,推荐加签或IP白名单),POST JSON消息体,含msgtype="text"或msgtype="markdown",标题建议包含环境(如【PROD】)、服务名、异常类名
- 邮件:使用JavaMailSender(Spring Boot场景)或javax.mail原生API;收件人可配置为运维组邮箱列表;正文应包含异常堆栈摘要(避免全量,防止邮件过大)、发生时间、JVM PID、主机名
- 建议增加限流:如10分钟内同类异常(相同class+相同message前50字符)只发1次,防刷屏
增强可观测性:结合MDC与上下文信息
纯异常堆栈价值有限,加入业务上下文才能快速定位问题:
- 在Web层(如Spring MVC拦截器)或RPC入口处,将traceId、userId、requestUri等写入MDC(Mapped Diagnostic Context)
- 在UncaughtExceptionHandler中通过MDC.get("traceId")读取,一并写入告警内容
- 若使用Logback,还可配置%X{traceId}让日志自动携带,便于关联排查
生产注意事项:异步、降级与配置化
告警本身不能拖慢主流程,也不能因告警失败导致业务异常:
- 通知逻辑必须异步执行(如提交至独立线程池),禁止阻塞原异常线程
- 钉钉/邮件客户端需设置超时(建议≤3s)和重试(最多1次),失败时记录本地error日志,不抛出新异常
- 开关应可动态控制(如配置中心拉取alert.enabled=true),灰度期或压测时可关闭
- 敏感信息(如手机号、身份证)需在告警前脱敏,避免泄露
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











