##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);
}