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

J2EE 異常處理框架設計:分層職責與棧跡保全

     編輯:J2EE

異常體系速覽

Java 異常繼承自 Throwable,分兩大支系:

  • Error:JVM 級嚴重問題(如 OutOfMemoryError),應用無需捕獲。
  • Exception:應用級異常,再分:
    • RuntimeException(非受檢):編程錯誤(空指針、越界、類型轉換),不應捕獲處理,而應修復代碼。
    • Checked Exception(受檢):業務可預期、可恢復的異常(業務規則違反、資源不存在),必須聲明拋出或捕獲處理。
從責任視角:Error→JVM、RuntimeException→程式設計師、Checked Exception→具體應用業務邏輯。

核心原則:分層過濾,絕不向上拋漏 RuntimeException

// 表現層(Action/Controller)統一入口
public void doAction(...) {
    try {
        bizService.doBusiness();
    } catch (Exception e) {
        if (e instanceof RuntimeException) {
            // 記錄日誌、通知開發人員、返回友好錯誤頁
            logger.error("程式設計錯誤", e);
            notifyDevTeam(e);
            return "error/500";
        } else {
            // 受檢異常:轉換為用戶可讀提示
            return "error/bizError"; // 攜帶 e.getMessage()
        }
    }
}

異常類體系設計

1. 基礎應用異常:ApplicationException

  • 繼承 Exception(受檢)
  • 支援異常鏈:cause 欄位 + initCause() + 重寫 getMessage()/printStackTrace() 遞歸輸出完整鏈路
  • 實現 getCause() 兼容 JDK 1.4+
public class ApplicationException extends Exception {
    protected Throwable cause;
    public ApplicationException() { super("Error occurred in application."); }
    public ApplicationException(String msg) { super(msg); }
    public ApplicationException(String msg, Throwable cause) { super(msg); this.cause = cause; }
    public Throwable initCause(Throwable cause) { this.cause = cause; return cause; }
    @Override public String getMessage() {
        String msg = super.getMessage();
        Throwable parent = this, child;
        while ((child = getNestedException(parent)) != null) {
            String msg2 = child.getMessage();
            if (msg2 != null) msg = (msg != null) ? msg + ": " + msg2 : msg2;
            if (child instanceof ApplicationException) break;
            parent = child;
        }
        return msg;
    }
    // printStackTrace() 同理遞歸輸出 "Caused by:" 鏈路
    protected Throwable getNestedException(Throwable t) { /* 反射獲取 cause 欄位 */ }
}

2. 業務異常:XXXBusinessException

public class XXXBusinessException extends ApplicationException {
    public XXXBusinessException(String msg) { super(msg); }
    public XXXBusinessException(Throwable cause) { super(cause.getMessage(), cause); }
}

服務層異常包裝模式

public void doBusiness() throws XXXBusinessException {
    try {
        executeStep1(); // 可能拋出 SQLException、RemoteException 等受檢異常
        executeStep2();
    } catch (Exception e) {
        // 關鍵:過濾 RuntimeException,不包裝!
        if (!(e instanceof RuntimeException)) {
            throw new XXXBusinessException(e);
        }
        throw e; // 保持原樣拋出,讓表現層統一處理
    }
}
錯誤示範:catch(Exception e){ throw new BizException(e); } 會吞沒 RuntimeException,導致程式設計錯誤偽裝成業務異常,掩蓋根因。

五條鐵律總結

  1. 應用異常必須繼承 Exception(受檢),絕不繼承 RuntimeException。
  2. 每層包裝時必須過濾 RuntimeException,直接向上拋出。
  3. 異常鏈完整保全:構造異常時帶上 cause,重寫 getMessage/printStackTrace 遞歸輸出。
  4. 表現層統一捕獲:RuntimeException→記錄/告警/友好頁;受檢異常→轉用戶提示。
  5. 職責分離:JVM 管 Error,開發者管 RuntimeException(修代碼),業務邏輯管 Checked Exception(業務規則)。

實戰建議

  • 定義模組級業務異常基類(ModuleBizException),細分錯誤碼(Enum)而非靠字符串。
  • 配合 AOP/攔截器實現全局異常處理,避免 Controller 重複 try-catch。
  • 日誌記錄時務必 logger.error(msg, e) 保留完整堆疊,禁止 e.getMessage() 入庫。
  • REST API 統一返回 {code, message, traceId},前端據碼顯示國際化提示。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved