1. 程式人生 > >java平臺統一異常框架的設計與實現

java平臺統一異常框架的設計與實現

在一個framework的設計中,異常框架的設計佔據著很重要的位置,因為它會直接影響到整個應用的健壯性、穩定性和易用性,因此筆者結合自己在產品開發中的經驗給出了一個異常框架的設計及實現與大家共享,有考慮不周或欠妥的地方還望大家一起討論,共同提高。

異常框架的總體結構圖

11.1異常框架總體結構圖

如上圖所示,java平臺框架的異常機制包括程式異常及業務異常。對於程式異常和業務異常我們設計一個BaseException基類,BaseException是一個unchecked exception(即繼承於RuntimeException),javaeye上有一篇關於checked exception
unchecked exception的討論長達幾十頁,偶在此就不多做解釋了,基於此平臺框架進行開發的應用可以對BaseException進行派生,例如BizFocus-workflow封裝了PersistenceExceptionServiceException來對應於持久層異常和業務層異常。持久層和業務層的異常在捕獲之後通過log4j輸出到了程式日誌,然後繼續向外拋給展現層的Action控制類,Action不需要對異常進行捕獲,因為BizFocus-workflow提供了一個基於webwork的異常攔截器(ExceptionInterceptor)對所有的Action的異常進行攔截。攔截後不同的異常在異常的國際化檔案中取得異常提示資訊展示給終端使用者。
1.2.1異常資訊的國際化封裝 如圖1.1所示,異常資訊的國際化封裝主要由Messages介面及其實現類MessageImplMessage_CN.propertiesMessage.properties兩個國際化檔案組成。 Messages介面如下: public interface Messages {     public static final int ERROR_UNKNOWN = 0;     public static final int ERROR_SYSTEM = 1;     public static final int ERROR_WORKFLOW = 2;
    public static final int NO_DECISIONVALUE_SET = 3; ………//其它的異常程式碼 } MessageImpl實現類的程式碼如下: public class MessageImpl implements Messages {     public MessageImpl() {     }     public static String getFormattedMessage(int i, Object aobj[]) {         String s;         try {             s = bundle.getString(String.valueOf(i));             if (aobj != null)                 s = MessageFormat.format(s, aobj);         }         catch (MissingResourceException missingresourceexception) {             s = missingresourceexception.getMessage();         }         return s;     } private static ResourceBundle bundle = ResourceBundle.getBundle("com.xxx.common.MessagesCN"); Message.properties國際化檔案如下: 0 = Unknown error 1 = System error 2 = Workflow error 3 = No decision vlaue was set ……其它異常資訊 Message_CN.properties檔案內容如下: 0 = 未知的錯誤 1 = 系統錯誤 2 = 工作流錯誤 3 = 您沒有設定工作流分支節點的決策值 ……其它異常資訊 1.2.2業務層和持久層異常的國際化處理 對於業務層和持久層異常的處理可以按照如下方式進行:         try {             //業務邏輯程式碼……         } catch (XXXException  ex) {             if (log.isDebugEnabled())//如果是debug狀態,直接輸出異常的堆疊呼叫順序                 ex.printStackTrace();             else//不是debug狀態,則只輸出異常資訊到日誌檔案                 log.error(BaseException.getLocalizedMessage(Messages.ERROR_WORKFLOWENGINE, null), ex);               throw new ServiceException(ex);//最後將異常拋給外層         } 1.2.3展現層異常的國際化處理 持久層和業務層的異常首先拋給了展現層的Action,在Action中對Exception不做任何處理直接丟擲,例如Action的程式碼如下: public String execute() throws Exception {//Exception直接丟擲        //控制邏輯的程式碼…… } 1.2.4通過webwork攔截器實現異常資訊在介面的展示 在上一節中,ActionException直接丟擲,因此在webwork攔截器中,對Exception進行攔截,將攔截的Exception進行分類,根據分類取得相關的異常提示資訊,然後傳給統一的異常顯示頁面,使用者在異常頁面上就會看到不同的異常資訊。ExceptionInterceptor程式碼示例如下: public class ExceptionInterceptor implements Interceptor {     private static final Log log = LogFactory.getLog(ExceptionInterceptor.class);     public static final String EXCEPTION = "exception";     public void destroy() {         //To change body of implemented methods use File | Settings | File Templates.     }     public void init() {         //To change body of implemented methods use File | Settings | File Templates.     }     public String intercept(ActionInvocation invocation) throws Exception {       String tipMessge = null;//中文提示資訊       String detailMessage = null;//詳細的錯誤資訊 try {             return invocation.invoke();         } catch (Exception e) {             if (e instanceof PersistenceException){//判斷程式異常的型別               //從國際化檔案中取得相應的錯誤提示資訊  tipMessge = ErrorMessage.getLocalizedMessage(Messages.ERROR_PERSISTENCELAYER);             }else if(e instanceof ServiceException){//判斷程式異常的型別 tipMessge = ErrorMessage.getLocalizedMessage(Messages.ERROR_SERVICELAYER); }             //詳細的錯誤資訊棧 detailMessage  =  invocation.getAction();             return EXCEPTION;//webwork將導向EXCEPTION對應的錯誤資訊頁面,common/exception.ftl         }     } } 上述程式碼是一個比較詳細的異常攔截器的程式碼,業務端可以基於此攔截器進行繼承,然後就可以很詳細地定製自己在開發過程中的異常。 common/exception.ftl頁面的程式碼如下: <table align="left" class="common_input_table" style="width:100%;height:100%">         <tr>             <td align="center" class="common_td_lable">${action.getText('bizfocus.ui.errorPageTitle')}</td>         </tr>         <tr>         <td align="center" class="common_td_text" >             <div align="center">                 <br><br><br><br>                 <@ww.if test="errorMessage==null">                 `   <font color="red">${action.getText('bizfocus.ui.errormessage')}</font>                 </@ww.if>                 <@ww.else>                    <a href=”detailMessage.action?detailMessage=<@ww.property value=’detailMessage’/>”> <font color="red"><@ww.property value="tipMessage"/></font>                 </@ww.else>             </div>         </td>         </tr>     </table> 1.3 業務異常的擴充套件 業務異常的處理,是在開發過程中經常遇到的問題,例如工作流引擎提供的根據業務資料自動決策分支節點的路由功能中,如果業務資料沒有傳遞給工作流引擎,則應該丟擲一個沒有設定決策資料的業務異常(NoDecisionValueSetException),因此在開發業務的過程中,開發者可以根據實際的業務情況進行異常類的定製開發,最後這些業務異常同樣被開發者自己擴充套件的異常攔截器進行攔截,最後根據業務異常的種類將不同的業務異常提示資訊展示給終端使用者(例如:您沒有設定決策資料給工作流引擎)。