Apache Commons Lang 的 ExceptionUtils 可快速提取业务异常根源,通过 getRootCause 获取最内层异常,getStackTrace 打印其堆栈,并可用 getRootCauseStackTrace 结合包名过滤精简日志,再配合 SLF4J MDC 添加 traceId、userId 等上下文提升排查效率。
使用 apache commons lang 的 exceptionutils 可以快速提取“业务相关”的异常根源,跳过 spring、tomcat、servlet 等框架层的冗余堆栈,让日志更聚焦问题本质。
引入依赖确保可用 ExceptionUtils
确认项目中已引入 commons-lang3(3.12.0+ 推荐):
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.14.0</version> </dependency>
注意:不要用旧版 commons-lang(2.x),它没有 ExceptionUtils 的现代过滤方法。
用 getRootCause + getStackTrace 聚焦根本原因
多数深层异常(如数据库连接失败、空指针)被层层包装(RuntimeException → ServiceException → WebException),直接打印 e.printStackTrace() 会淹没关键行。推荐组合使用:
-
ExceptionUtils.getRootCause(e):穿透所有包装异常,拿到最内层原始异常(如SQLException或NullPointerException) -
ExceptionUtils.getStackTrace(cause):仅打印该根源异常的完整堆栈(不含外层包装类的无关调用帧)
示例代码:
立即学习“Java免费学习笔记(深入)”;
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
import org.apache.commons.lang3.exception.ExceptionUtils;
try {
// 业务逻辑
} catch (Exception e) {
Throwable root = ExceptionUtils.getRootCause(e);
log.error("业务异常: {} \n{}", root, ExceptionUtils.getStackTrace(root));
}
进一步精简:用 getRootCauseStackTrace 过滤框架包名
若连根源异常的堆栈里仍有大量 org.springframework.*、javax.servlet.* 等非业务代码,可用:
-
ExceptionUtils.getRootCauseStackTrace(e):返回String[],每行为一行堆栈;可遍历过滤掉含指定包名的行 - 手动保留以你公司包名(如
com.yourcompany.service.)或核心工具类开头的行
轻量过滤示例:
String[] trace = ExceptionUtils.getRootCauseStackTrace(e);
List<String> cleanTrace = Arrays.stream(trace)
.filter(line -> line.contains("com.yourcompany.") ||
line.contains("Caused by:") ||
line.startsWith("\tat "))
.collect(Collectors.toList());
log.error("精简堆栈:\n{}", String.join("\n", cleanTrace));
配合 SLF4J MDC 实现上下文增强
光精简堆栈不够,还需定位具体请求。在捕获异常前把关键上下文写入 MDC:
MDC.put("traceId", UUID.randomUUID().toString())MDC.put("userId", currentUser.getId())
再配合 Logback 的 %X{traceId} 模板,日志自动带上追踪标识,和精简堆栈结合,排查效率翻倍。


















