天天看點

java todo error_Java全局異常處理(TODO)

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

}