Java如何创建独立监听器监听项目内捕获的异常并通过Log4j记录日志?
全局捕获异常并自动执行代码的几种优雅方案
当然可以!你完全不用在每个try-catch块里重复编写Log4j日志代码,下面几种方案能帮你实现全局捕获异常并自动执行自定义逻辑,彻底摆脱重复劳动:
方案1:普通Java项目的全局未捕获异常处理器
如果你的项目不是Spring体系,可以利用Java自带的Thread.UncaughtExceptionHandler来处理线程中未被手动捕获的异常。
首先写一个全局异常处理类:
public class GlobalExceptionHandler implements Thread.UncaughtExceptionHandler { private static final Logger logger = LogManager.getLogger(GlobalExceptionHandler.class); @Override public void uncaughtException(Thread t, Throwable e) { // 这里执行你的自定义逻辑,比如日志记录 logger.error("线程[" + t.getName() + "]发生未捕获异常", e); // 还可以扩展其他操作,比如发送报警通知、记录异常到数据库等 } }
然后在项目启动时设置全局处理器:
// 设置给所有线程的默认处理器 Thread.setDefaultUncaughtExceptionHandler(new GlobalExceptionHandler()); // 如果用线程池,创建时指定处理器 ExecutorService executor = Executors.newFixedThreadPool(10, r -> { Thread thread = new Thread(r); thread.setUncaughtExceptionHandler(new GlobalExceptionHandler()); return thread; });
方案2:Spring/Spring Boot项目的全局异常处理器
如果是Spring生态的项目,@ControllerAdvice(或@RestControllerAdvice)是处理Controller层异常的绝佳选择,配合@ExceptionHandler可以精准捕获不同类型的异常:
@ControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LogManager.getLogger(GlobalExceptionHandler.class); // 捕获所有Exception类型的异常 @ExceptionHandler(Exception.class) public ResponseEntity<String> handleAllExceptions(Exception e) { logger.error("捕获到全局异常", e); // 这里可以返回统一的错误响应,也可以只执行日志逻辑 return new ResponseEntity<>("服务器内部错误", HttpStatus.INTERNAL_SERVER_ERROR); } // 针对特定异常单独处理(比如空指针异常) @ExceptionHandler(NullPointerException.class) public ResponseEntity<String> handleNullPointerException(NullPointerException e) { logger.error("捕获到空指针异常", e); return new ResponseEntity<>("参数为空,请检查输入", HttpStatus.BAD_REQUEST); } }
注意:这个方案主要覆盖Controller层的异常,如果要捕获Service层、工具类等非Web层的异常,建议结合下面的AOP方案。
方案3:用AOP(面向切面编程)全局拦截所有异常
不管是Spring还是普通Java项目(借助AspectJ),AOP都能帮你拦截指定范围内所有方法的异常,彻底实现无侵入式的异常处理。
以Spring AOP为例,先写一个切面类:
@Aspect @Component public class ExceptionLoggingAspect { private static final Logger logger = LogManager.getLogger(ExceptionLoggingAspect.class); // 定义切点:拦截com.yourpackage包下所有类的所有方法(根据你的项目调整包路径) @Pointcut("execution(* com.yourpackage..*(..))") public void allBusinessMethods() {} // 当方法抛出异常时触发通知 @AfterThrowing(pointcut = "allBusinessMethods()", throwing = "exception") public void logException(JoinPoint joinPoint, Throwable exception) { String className = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); logger.error("类[" + className + "]的方法[" + methodName + "]抛出异常", exception); // 这里可以添加任何你需要的自定义逻辑 } }
这个切面会自动拦截指定包下所有方法抛出的未被捕获的异常,自动记录日志。如果有些方法必须用try-catch处理业务逻辑,建议在catch块中把异常重新抛出(比如包装成自定义异常),这样AOP依然能捕获到并执行日志逻辑。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

