Spring AOP學習筆記
通常我們對于異常的處理方式都是大同小異的,要么直接捕獲并處理,要么讓它拋向上一層,要么就是記錄到日志里,或者發郵件提供管理員,但這樣下來一個項目中便會到處充斥著 try/catch ,并且 catch 中的代碼基本類似,于是我們聞到的其中難聞的壞味道。
本文將介紹如何通過 Spring.AOP 特性實現異常的統一處理,如果我們需要在異常發生時做一些操作的話我們就必須實現 Spring.Aop.IThrowsAdvice,該接口沒有任何實現方法,是一個空接口,它僅僅做為一個標記接口而存在,但實現了 IThrowsAdvice 接口的類必須定義至少一個 AfterThrowing 方法,方法的簽名如下:AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass);
其中中括號括起來的前三個參數是可選的,返回值可以是任意數據類型。 Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptor 類實現對實現了 Spring.Aop.IThrowsAdvice 派生類中的方法依賴注入,其中的 ThrowsAdviceInterceptor() 方法檢查 Spring.Aop.IThrowsAdvice 的派生類是否定義了至少一個異常處理方法,如果沒有則拋出 ArgumentException 異常,MapAllExceptionHandlingMethods()方法則在定義好的重載方法中查找出異常類型與最后一個參數所定義的類型中最接近的方法,而且我們不應該在其中實現了兩個相同異常類型的方法,即使他們的參數數目不同,否則也將拋出 ArgumentException 異常。
[下面引用自《Spring 技術手冊》第4章 P94 頁中的一段話]注意到當異常發生時, Throw Advice 的任務只是執行對應的方法,您并不能在 Throw Advice 中將異常處理掉,在 Throw Advice 執行完畢后,原告的異常仍將傳播至應用程序之中, Throw Advice 并不介入應用程序的異常處理,異常處理仍舊是應用程序本身所要負責的,如果想要在 Throw Advice 處理時中止應用程序的處理流程,作法是拋出其它的異常。
接下來看個 Throws Advice 的實際例子,首先定義 IHello 接口:
- using System;
- namespace TestThrowAdvice
- {
- public interface IHello
- {
- void Hello(string name);
- }
- }
接著定義一個 HelloSpeaker 類來實現 IHello 接口,并在 Hello() 方法中模擬程序發生錯誤時的異常拋出:
- using System;
- namespace TestThrowAdvice
- {
- public class HelloSpeaker : IHello
- {
- public void Hello(string name)
- {
- Console.WriteLine("Hello, " + name);
- //抱歉! 程序錯誤! 發生異常 XD
- throw new Exception("發生異常");
- }
- }
- }
如果您需要在應用程序拋出異常時,介入 Throw Advice 提供一些服務,例如記錄一些異常信息,則可以實現 Spring.Aop.IThrowsAdvice 接口,在這個例子中我使用了 log4net 組件來實現日志的記錄:
- using System;
- using Spring.Aop;
- using log4net;
- using log4net.Core;
- using System.Reflection;
- [assembly: log4net.Config.XmlConfigurator(Watch = true)]
- namespace TestThrowAdvice
- {
- public class SomeThrowAdvice : IThrowsAdvice
- {
- private ILog logger;
- public SomeThrowAdvice()
- {
- logger = LogManager.GetLogger(this.GetType());
- }
- public void AfterThrowing(MethodInfo method, Object[] args, Object target, Exception exception)
- {
- // 記錄異常
- logger.Info("記錄異常", exception);
- }
- }
- }
接著在配置文件(我這里使用了獨立配置文件)中寫下以下的定義,讓 Throw Advice 在異常發生時提供記錄服務:
- xml version="1.0" encoding="utf-8"?>
- <objects xmlns="http://www.Springframework.net" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.Springframework.net
- http://www.Springframework.net/xsd/Spring-objects.xsd">
- <object id="SomeThrowAdvice" type="TestThrowAdvice. SomeThrowAdvice, TestThrowAdvice" />
- <object id="HelloSpeaker" type="TestThrowAdvice.HelloSpeaker, TestThrowAdvice" />
- <object id="HelloProxy" type="Spring.Aop.Framework. ProxyFactoryObject, Spring.Aop" >
- <property name="ProxyInterfaces">
- <list>
- <value>TestThrowAdvice.IHello,TestThrowAdvice< SPAN>value>
- < SPAN>list>
- < SPAN>property>
- <property name="Target">
- <ref object="HelloSpeaker" />
- < SPAN>property>
- <property name="InterceptorNames">
- <list>
- <value>SomeThrowAdvice< SPAN>value>
- < SPAN>list>
- < SPAN>property>
- < SPAN>object>
- < SPAN>objects>
最后剩下我們的程序入口 Main() 函數了:
- using System;
- using Spring.Context;
- using Spring.Context.Support;
- namespace TestThrowAdvice
- {
- public class Program
- {
- static void Main(string[] args)
- {
- log4net.Config.XmlConfigurator.Configure();
- IApplicationContext context = new XmlApplicationContext(@"../../SpringNet.xml");
- IHello helloProxy = (IHello)context.GetObject("HelloProxy");
- try
- {
- helloProxy.Hello("Justin");
- }
- catch (Exception ex)
- {
- // 應用程序的異常處理
- Console.WriteLine(ex.Message);
- }
- }
- }
- }
【編輯推薦】