##spring mvc全局异常处理
##原生servlet全局异常处理
##非web java程序全局异常处理.
##对未捕获异常进行记录
###使用Thread产生的异常. 使用Thread的方法有两种:
继承Thread重载run方法
创建Runnable传给Thread
这两种方式,执行代码都是放在run方法里的.如果run方法抛出了RuntimeException,我们怎么才能知道呢. Thread有一个静态方法setDefaultUncaughtExceptionHandler和一个普通方法setUncaughtExceptionHandler,是用来处理这种异常的. 默认的handler在遇到异常时,会把异常堆栈打印到System.err.是的,就像我们通常所见的那样,红字打印到控制台. 如果想要把这些异常也用logger工具记录的话,就要设置我们自定义的UncaughtExceptionHandler了.
###使用线程池产生的异常 提到线程池,也就是1.5之后新增的并发库了.常用的实现类就是ThreadPoolExecutor了. ThreadPoolExecutor有submit方法和execute方法,这两种方法都是用来提交执行任务的,他们的区别在于一种返回Future而另一种返回空.
对于Future的情况,执行任务期间产生的异常都被重新包装为ExecutionException,只有任务执行完成调用Future#get方法的时候,这个异常才会被抛出.
对于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);
}