Java全局异常处理(TODO)

spring mvc全局异常处理

原生servlet全局异常处理

非web java程序全局异常处理.

对未捕获异常进行记录

使用Thread产生的异常.

使用Thread的方法有两种:

  1. 继承Thread重载run方法
  2. 创建Runnable传给Thread

这两种方式,执行代码都是放在run方法里的.如果run方法抛出了RuntimeException,我们怎么才能知道呢.
Thread有一个静态方法setDefaultUncaughtExceptionHandler和一个普通方法setUncaughtExceptionHandler,是用来处理这种异常的.
默认的handler在遇到异常时,会把异常堆栈打印到System.err.是的,就像我们通常所见的那样,红字打印到控制台.
如果想要把这些异常也用logger工具记录的话,就要设置我们自定义的UncaughtExceptionHandler了.

使用线程池产生的异常

提到线程池,也就是1.5之后新增的并发库了.常用的实现类就是ThreadPoolExecutor了.
ThreadPoolExecutor有submit方法和execute方法,这两种方法都是用来提交执行任务的,他们的区别在于一种返回Future而另一种返回空.

  1. 对于Future的情况,执行任务期间产生的异常都被重新包装为ExecutionException,只有任务执行完成调用Future#get方法的时候,这个异常才会被抛出.
  2. 对于execute方法.执行任务期间产生的异常会被记录,然后在执行ThreadPoolExecutor#afterExecute方法时作为参数传入.由于该方法默认为空,所以这种情况下异常就像被吃掉一样莫名其妙消失了.

如何对上面两种情况产生的异常进行记录? 第二种比较简单,重载afterExecute进行记录即可.而第一种情况则需要一个恰当的时间点:在任务执行完成之后,调用get方法,然后捕获并记录异常.刚刚提到的afterExecute方法正好符合这个契机.所以这两种情况都可以放在afterExecute中进行处理.
处理代码类似于这样(参考链接):

protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    printException(r, t);
}

private static void printException(Runnable r, Throwable t) {
    if (t == null && r instanceof Future<?>) {
        try {
            Future<?> future = (Future<?>) r;
            if (future.isDone())
                future.get();
        } catch (CancellationException ce) {
            t = ce;
        } catch (ExecutionException ee) {
            t = ee.getCause();
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt(); // ignore/reset
        }
    }
    if (t != null)
        log.error(t.getMessage(), t);
}

你可能感兴趣的:(Java全局异常处理(TODO))