背景
這篇文章介紹的異常處理思路不錯,本文試圖給出一種具體實現,當然可能和作者的思路有所不同。
框架地址:https://github.com/happyframework/HappyFramework。
框架介紹
關於異常的一些想法:
- 異常不能跨越“邊界類”。
- 在邊界類之下,異步不能被“吞掉”。
- 系統在不同場景或分層中,需要的不同的處理“策略”。
- 每種策略都是一個可擴展的“管道”。
- 可以和 AOP 進行集成。
- 異常可以用來給業務用戶提供“提醒”。
- 異常可以給運維用戶提供“日志”。
我希望異常處理框架以某種機制支持上面的各種想法。
針對邊界類的處理場景
模擬的邊界類
1 package com.happyframework.exception.handling; 2 3 import org.springframework.stereotype.Controller; 4 5 import com.happyframework.exception.handling.springframework.HandleException; 6 7 @Controller 8 public class TestController { 9 10 @HandleException("UI") 11 public void test() { 12 throw new RuntimeException("業務失敗"); 13 } 14 15 }
因為邊界類需要特殊的異常處理策略,這里指定了的策略名字為:“UI”。
“UI”策略對應的管道配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:p="http://www.springframework.org/schema/p" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xmlns:mvc="http://www.springframework.org/schema/mvc" 7 xmlns:aop="http://www.springframework.org/schema/aop" 8 xmlns:util="http://www.springframework.org/schema/util" 9 xsi:schemaLocation="http://www.springframework.org/schema/beans 10 http://www.springframework.org/schema/beans/spring-beans.xsd 11 http://www.springframework.org/schema/context 12 http://www.springframework.org/schema/context/spring-context.xsd 13 http://www.springframework.org/schema/mvc 14 http://www.springframework.org/schema/mvc/spring-mvc.xsd 15 http://www.springframework.org/schema/aop 16 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 17 http://www.springframework.org/schema/util 18 http://www.springframework.org/schema/util/spring-util-3.0.xsd"> 19 20 <context:component-scan base-package="com.happyframework.exception.handling.springframework" /> 21 <context:component-scan base-package="com.happyframework.exception.handling" /> 22 23 <aop:aspectj-autoproxy/> 24 25 <bean class="com.happyframework.exception.handling.springframework.ExceptionHandlerDefination"> 26 <property name="policy" value="UI"/> 27 <property name="handler"> 28 <bean class="com.happyframework.exception.handling.ConsoleLoggingHandler"/> 29 </property> 30 </bean> 31 <bean class="com.happyframework.exception.handling.springframework.ExceptionHandlerDefination"> 32 <property name="policy" value="UI"/> 33 <property name="handler"> 34 <bean class="com.happyframework.exception.handling.ConsoleNotificationHandler"/> 35 </property> 36 </bean> 37 </beans> 38
為管道定義了兩個處理器:日志處理器和提醒處理器,因為是測試的處理器,實現就比較簡單,真實項目中可以決定:哪些異常需要日志?哪些信息提醒給用戶?
運行輸出
1 記錄日志:java.lang.RuntimeException: 業務失敗 2 提示消息:java.lang.RuntimeException: 業務失敗
“UI”策略導致異常被吞掉了,這也是我們期望的行為,后面會介紹如何在處理器中吞掉異常。
核心 API 介紹
主要類型
代碼可以去 https://github.com/happyframework/HappyFramework 下載。
重點說一下 ExceptionHandlerChain
1 package com.happyframework.exception.handling; 2 3 public interface ExceptionHandlerChain { 4 5 Throwable getException(); 6 7 void setNewException(final Throwable newException); 8 9 boolean isExceptionHandled(); 10 11 void setExceptionHandled(final boolean exceptionHandled); 12 13 void proceed(); 14 15 }
ExceptionHandlerChain 是作為參數傳遞給 ExceptionHandler:
1 package com.happyframework.exception.handling; 2 3 public interface ExceptionHandler { 4 5 void handle(final ExceptionHandlerChain chain); 6 7 }
ExceptionHandlerChain 的成員的主要意圖是:
- Throwable getException():返回正在處理的異常。
- void setNewException(final Throwable newException):替換或包裝異常的時候調用此方法。
- boolean isExceptionHandled():異常是否被處理過。
- void setExceptionHandled(final boolean exceptionHandled):吞掉異常的時候調用此方法。
- void proceed():執行下一個處理器。
一個簡單的異常處理器
1 package com.happyframework.exception.handling; 2 3 final class ConsoleNotificationHandler implements ExceptionHandler { 4 5 @Override 6 public final void handle(final ExceptionHandlerChain chain) { 7 System.out.println("提示消息:" + chain.getException()); 8 9 chain.setExceptionHandled(true); 10 chain.proceed(); 11 } 12 13 }
備注
第一次用 Java 寫東西,感覺挺不錯的。