首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

借鑑 Acegi ExceptionTranslationFilter 設計優雅的異常處理架構

     編輯:Java 相關知識

Acegi 將「業務攔截」與「異常處理」分離:FilterSecurityInterceptor 專職決策、拋出異常;ExceptionTranslationFilter 專職捕獲、轉換為 HTTP 回應。這種職責分離思想極具參考價值。

一、Acegi 異常處理流程

  1. 請求通過 Filter 鏈抵達 FilterSecurityInterceptor。
  2. 決策失敗拋出 AccessDeniedException 或 AuthenticationException。
  3. 上層 ExceptionTranslationFilter 捕獲,委派 AuthenticationEntryPoint(導向登入)或 AccessDeniedHandler(403 頁面)。
  4. Servlet 容器回應對應 HTTP 狀態碼與頁面。

二、反面教材:業務方法吞噬異常

protected String sendAlertMessage(String to, String subject, String msg, String from) {
    SimpleMailMessage mail = createMessage(to, subject, msg, from);
    try {
        mailEngine.sendEmail(mail);
    } catch (MailException ex) {
        log.error(ex.getMessage()); // 僅記錄
        return ex.getMessage();     // 回傳 String,呼叫端失去型別資訊
    }
    return "1";
}

缺點:

  • 異常層級扁平化,呼叫端無法針對 MailAuthenticationException、MailSendException 分流處理。
  • 錯誤上下文丟失(如寄件人真實姓名),無法生成友善錯誤訊息。
  • 違反「拋出異常給能處理的層級」原則。

三、重構建議:分離關注點

// 1. 定義業務異常層級
public class MailSendFailedException extends RuntimeException {
    private final MailException cause;
    private final String fromRealName;
    // 建構子、Getter...
}

// 2. 底層僅轉換,不吞噬
public void send(SimpleMailMessage mail) {
    try {
        mailEngine.sendEmail(mail);
    } catch (MailException ex) {
        throw new MailSendFailedException("郵件發送失敗", ex, fromRealName);
    }
}

// 3. 控制層/切面統一處理
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MailSendFailedException.class)
    public ResponseEntity<ErrorResponse> handle(MailSendFailedException ex) {
        String msg = String.format("由 %s 發送給 %s 的郵件因 %s 失敗",
                ex.getFromRealName(), ex.getTo(), ex.getCause().getClass().getSimpleName());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                             .body(new ErrorResponse(msg));
    }
}

四、設計原則總結

  1. 單一職責:業務邏輯拋出異常,基礎設施層轉換/豐富異常,表現層決定 HTTP 回應。
  2. 保留型別:勿將檢查型異常包裝為無意義 String/ErrorCode。
  3. 全域攔截:利用 AOP / Filter / ControllerAdvice 集中處理,避免重複 try-catch。
  4. 失敗資訊完整:異常攜帶足夠上下文(用戶、操作、參數)供錯誤頁面/日誌使用。

五、啟發

框架級程式碼的異常處理往往是最佳範本。閱讀 Spring Security、Netty、Dubbo 等原始碼的異常體系,能顯著提升架構設計能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved