通常我們對(duì)于異常的處理方式都是大同小異的,要么直接捕獲并處理,要么讓它拋向上一層,要么就是記錄到日志里,或者發(fā)郵件提供管理員,但這樣下來一個(gè)項(xiàng)目中便會(huì)到處充斥著 try/catch ,并且 catch 中的代碼基本類似,于是我們聞到的其中難聞的壞味道。
本文將介紹如何通過
Spring.
Net 的 AOP 特性實(shí)現(xiàn)異常的統(tǒng)一處理,如果我們需要在異常發(fā)生時(shí)做一些操作的話我們就必須實(shí)現(xiàn)
Spring.Aop.IThrowsAdvice,該接口沒有任何實(shí)現(xiàn)方法,是一個(gè)空接口,它僅僅做為一個(gè)標(biāo)記接口而存在,但實(shí)現(xiàn)了 IThrowsAdvice 接口的類必須定義至少一個(gè) AfterThrowing 方法,方法的簽名如下:
AfterThrowing([MethodInfo method, Object[] args, Object target], Exception subclass);
其中中括號(hào)括起來的前三個(gè)參數(shù)是可選的,返回值可以是任意數(shù)據(jù)類型。Spring.Aop.Framework.Adapter.ThrowsAdviceInterceptor 類實(shí)現(xiàn)對(duì)實(shí)現(xiàn)了 Spring.Aop.IThrowsAdvice 派生類中的方法依賴注入,其中的 ThrowsAdviceInterceptor() 方法檢查 Spring.Aop.IThrowsAdvice 的派生類是否定義了至少一個(gè)異常處理方法,如果沒有則拋出 ArgumentException 異常,MapAllExceptionHandlingMethods() 方法則在定義好的重載方法中查找出異常類型與最后一個(gè)參數(shù)所定義的類型中最接近的方法,而且我們不應(yīng)該在其中實(shí)現(xiàn)了兩個(gè)相同異常類型的方法,即使他們的參數(shù)數(shù)目不同,否則也將拋出 ArgumentException 異常。
[下面引用自《Spring 技術(shù)手冊(cè)》第4章 P94 頁(yè)中的一段話]
注意到當(dāng)異常發(fā)生時(shí), Throw Advice 的任務(wù)只是執(zhí)行對(duì)應(yīng)的方法,您并不能在 Throw Advice 中將異常處理掉,在 Throw Advice 執(zhí)行完畢后,原告的異常仍將傳播至應(yīng)用程序之中, Throw Advice 并不介入應(yīng)用程序的異常處理,異常處理仍舊是應(yīng)用程序本身所要負(fù)責(zé)的,如果想要在 Throw Advice 處理時(shí)中止應(yīng)用程序的處理流程,作法是拋出其它的異常。
接下來看個(gè) Throws Advice 的實(shí)際例子,首先定義 IHello 接口:
using System;

namespace TestThrowAdvice


{
public interface IHello

{
void Hello(string name);
}
}
接著定義一個(gè) HelloSpeaker 類來實(shí)現(xiàn) IHello 接口,并在 Hello() 方法中模擬程序發(fā)生錯(cuò)誤時(shí)的異常拋出:
using System;

namespace TestThrowAdvice


{
public class HelloSpeaker : IHello

{
public void Hello(string name)

{
Console.WriteLine("Hello, " + name);
//抱歉! 程序錯(cuò)誤! 發(fā)生異常 XD
throw new Exception("發(fā)生異常
");
}
}
}


如果您需要在應(yīng)用程序拋出異常時(shí),介入 Throw Advice 提供一些服務(wù),例如記錄一些異常信息,則可以實(shí)現(xiàn) Spring.Aop.IThrowsAdvice 接口,在這個(gè)例子中我使用了 log4net 組件來實(shí)現(xiàn)日志的記錄:
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);
}
}
}
接著在配置文件(我這里使用了獨(dú)立配置文件)中寫下以下的定義,讓 Throw Advice 在異常發(fā)生時(shí)提供記錄服務(wù):
<?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</value>
</list>
</property>
<property name="Target">
<ref object="HelloSpeaker" />
</property>
<property name="InterceptorNames">
<list>
<value>SomeThrowAdvice</value>
</list>
</property>
</object>
</objects>

最后剩下我們的程序入口 Main() 函數(shù)了:
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)

{
// 應(yīng)用程序的異常處理
Console.WriteLine(ex.Message);
}
}
}
}
程序執(zhí)行結(jié)果輸出:
Hello, Justin
發(fā)生異常...
日志記錄中的結(jié)果:
2006-10-30 20:59:03,125 [4020] INFO TestThrowAdvice.SomeThrowAdvice - 記錄異常
System.Exception: 發(fā)生異常...
在 TestThrowAdvice.HelloSpeaker.Hello(String name) 位置 E:\..\..\SpringNetDemo\TestThrowAdvice\HelloSpeaker.cs:行號(hào) 14
在 Spring.Objects.ObjectUtils.InvokeMethod(MethodInfo method, Object instance, Object[] arguments) 位置 c:\projects\daily\Spring.Net\src\Spring\Spring.Core\Objects\ObjectUtils.cs:行號(hào) 489
在 Spring.Aop.Framework.ReflectiveMethodInvocation.InvokeJoinpoint() 。。。。。
本博客為學(xué)習(xí)交流用,凡未注明引用的均為本人作品,轉(zhuǎn)載請(qǐng)注明出處,如有版權(quán)問題請(qǐng)及時(shí)通知。由于博客時(shí)間倉(cāng)促,錯(cuò)誤之處敬請(qǐng)諒解,有任何意見可給我留言,愿共同學(xué)習(xí)進(jìn)步。