第五章 面向方面編程___通知類型


  前面兩節談到了 AOP 的概念以及我們使用代理模式來模擬了 AOP ,在代理類中,我們對所有的方法進行了攔截,並沒有做更細的處理。

Spring.Net 中幫我們提供了一套完善的 AOP 框架,對於目前絕大部分的需求都能夠提供完整的支持。Spring.Net 中幫我們提供了多種對方法的攔截的方式,這種對方法進行攔截的方式專業術語又稱 “通知” 。Spring.Net 的通知既可由某個類的所有對象共享,也可由該類型的單個實例獨占。共享的通知稱為基於類型(per-class)的通知,而獨占的通知稱為基於實例(per-instance)的通知。

  基於類型的通知最為常用。比如說事務,它就很適合用基於類型的通知實現。它們不依賴於目標對象的狀態,也不會向目標對象添加新狀態,僅僅對方法及其參數進行操作。

  基於實例的通知比較適合做引入 ( introductions ) 。此時通知可以向目標對象添加狀態。在 AOP 代理中,可以同時使用基於類型和基於實例的通知。

  Spring.Net 幫我們提供了以下通知:

around advice(環繞通知):最常用的通知類型,又稱為方法攔截器。環繞通知繼承自 IMethodInterceptor 接口,在攔截到方法之后,運行程序員在方法調用之前或之后做操作。

before advise(前置通知): 前置通知只在方法調用之前執行,前置通知需要繼承自 IMethodBeforeAdvice 接口。

after returning advise(后置通知): 后置通只在方法調用之后執行,后置通知需要繼承自 IAfterReturningAdvice 接口,如果通知拋出異常,就會沿攔截器鏈向上拋出,從而中斷攔截器鏈的繼續執行。

throws advise(異常通知): 異常通知只在發生異常的情況下執行。

IMethodInterceptor 環繞通知接口:

IMethodBeforeAdvice  前置通知接口 : 

IAfterReturningAdvice  后置通知接口 :

IThrowsAdvice  異常通知接口 :

我們還是來上代碼:

有一個銀行卡的接口,其中有兩個方法,存入 Deposit 和 支出 Pay

 1 namespace CnblogsLesson_5_2.Interface
 2 {
 3     public interface ICard
 4     {
 5         //存入
 6         void Deposit(double money);
 7 
 8         //支出
 9         void Pay(double money);
10     }
11 }

銀行卡的實現類:

 1 using System;
 2 using CnblogsLesson_5_2.Interface;
 3 
 4 namespace CnblogsLesson_5_2.Impl
 5 {
 6     public class Card : ICard
 7     {
 8 
 9         /// <summary>
10         /// 存入
11         /// </summary>
12         public void Deposit(double money)
13         {
14             throw new Exception();
15             Console.WriteLine("存入{0}元", money);
16         }
17 
18         /// <summary>
19         /// 支出
20         /// </summary>
21         public void Pay(double money)
22         {
23             Console.WriteLine("支出{0}元",money);
24         }
25         
26     }
27 }

  Spring.Net 的非侵入性,決定了幾乎所有的功能,都可以通過配置文件配置實現。而要實現 AOP 也是一樣的,也可以通過配置實現。在使用 Spring.Net  AOP 功能的時候,需要對項目引入 Spring.Aop.dll 文件。廢話不多說,我們來看一下怎么配置。我們現在要進行方法攔截,攔截到之后做一些事情。我們先得創建一些通知:

一 . 環繞通知

  如:環繞通知,我們在攔截到方法之后,可以做一些操作,比如在方法之前輸出一句話或在方法之后做一些事情。我們現在來添加一個 AroundAdvice 類,如下:

 1 using AopAlliance.Intercept;
 2 using System;
 3 
 4 namespace CnblogsLesson_5_2.Notify
 5 {
 6     /// <summary>
 7     /// 環繞通知
 8     /// </summary>
 9     public class AroundAdvice : IMethodInterceptor
10     {
11         public object Invoke(IMethodInvocation invocation)
12         {
13             Console.WriteLine("我是環繞通知,參數是{0},我在調用執行方法之前做了一件事!",invocation.Arguments);
14             //執行方法
15             object result = invocation.Proceed();
16             Console.WriteLine("我是環繞通知,返回值是{0},我在調用執行方法之后做了一件事!",result);
17             return result;
18         }
19     }
20 }

執行程序:

 1 using Spring.Context;
 2 using Spring.Context.Support;
 3 using CnblogsLesson_5_2.Interface;
 4 
 5 namespace CnblogsLesson_5_2
 6 {
 7     class Program
 8     {
 9         static void Main(string[] args)
10         {
11             IApplicationContext context = ContextRegistry.GetContext();
12 
13             ICard card = context.GetObject("card") as ICard;
14 
15             card.Pay(100);
16         }
17     }
18 }

看一下執行結果,可以看到,card 實例調用 Pay 方法 被攔截到的  環繞通知:

二 . 前置通知 

前置通知只在方法調用之前執行 :

 1 using Spring.Aop;
 2 using System;
 3 using System.Reflection;
 4 
 5 namespace CnblogsLesson_5_2.Notify
 6 {
 7     /// <summary>
 8     /// 方法前置通知
 9     /// </summary>
10     public class BeforeAdvice : IMethodBeforeAdvice
11     {
12         public void Before(MethodInfo method, object[] args, object target)
13         {
14             Console.WriteLine("方法前置通知調用:方法名稱為" + method.Name + "。參數為" + args + "。目標對象:" + target);
15         }
16     }
17 }

看一下執行結果,可以看到,card 實例調用 Pay 方法 被攔截到的  前置通知:

三 . 后置通知

后置通只在方法調用之后執行,后置通知需要繼承自IAfterReturningAdvice接口,如果通知拋出異常,就會沿攔截器鏈向上拋出,從而中斷攔截器鏈的繼續執行。

 1 using System;
 2 using Spring.Aop;
 3 
 4 namespace CnblogsLesson_5_2.Notify
 5 {
 6     public class AfterReturningAdvice : IAfterReturningAdvice
 7     {
 8         public void AfterReturning(object returnValue, System.Reflection.MethodInfo method, object[] args, object target)
 9         {
10             Console.WriteLine("開始調用方法后置通知:返回值為:" + returnValue + "。方法名稱為:" + method.Name + "。參數是:" + args + "。目標對象是:" + target);
11         }
12     }
13 }

看一下執行結果,可以看到,card 實例調用 Pay 方法 被攔截到的 后置通知:

四 . 異常通知

異常通知只在發生異常的情況下執行,我們之前在 Deposit 方法中,手動拋出異常,為 Deposit 方法添加異常通知后,Deposit 方法執行過程中出現異常,將會被異常通知捕獲到。

 1 using System;
 2 using CnblogsLesson_5_2.Interface;
 3 
 4 namespace CnblogsLesson_5_2.Impl
 5 {
 6     public class Card : ICard
 7     {
 8 
 9         /// <summary>
10         /// 存入
11         /// </summary>
12         public void Deposit(double money)
13         {
14             throw new Exception();
15             Console.WriteLine("存入{0}元", money);
16         }
17 
18         /// <summary>
19         /// 支出
20         /// </summary>
21         public void Pay(double money)
22         {
23             Console.WriteLine("支出{0}元",money);
24         }
25         
26     }
27 }

異常通知 類:

 1 using System;
 2 using Spring.Aop;
 3 
 4 namespace CnblogsLesson_5_2.Notify
 5 {
 6     /// <summary>
 7     /// 異常通知
 8     /// </summary>
 9     public class ThrowsAdvice : IThrowsAdvice
10     {
11         public void AfterThrowing(Exception ex)
12         {
13             Console.WriteLine("異常被觸發了");
14         }
15     }
16 }

通過執行程序,可以到看,Deposit 方法手動拋出異常,被異常通知捕獲到:

以上就是常用的四種通知類型,通過下面的配置文件,就可以知道 Spring.Net 中如何來配置它們:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <objects xmlns="http://www.springframework.net">
 3 
 4   <!--信用卡實例-->
 5   <object id="card" type="CnblogsLesson_5_2.Impl.Card,CnblogsLesson_5_2"/>
 6 
 7   <!--配置環繞通知-->
 8   <object id="aroundAdvice" type="CnblogsLesson_5_2.Notify.AroundAdvice, CnblogsLesson_5_2"></object>
 9   
10   <!--配置前置通知-->
11   <object id="beforeAdvice" type="CnblogsLesson_5_2.Notify.BeforeAdvice, CnblogsLesson_5_2"></object>
12   
13   <!--配置后置通知-->
14   <object id="afterReturningAdvice" type="CnblogsLesson_5_2.Notify.AfterReturningAdvice, CnblogsLesson_5_2"></object>
15   
16   <!--配置異常通知-->
17   <object id="throwsAdvice" type="CnblogsLesson_5_2.Notify.ThrowsAdvice, CnblogsLesson_5_2"></object>
18 
19   <!--配置AOP代理對象-->
20   <object id="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
21     <!--代理的目標對象列表,如目前只代理了card對象-->
22     <property name="ObjectNames">
23       <list>
24         <!--這里可能需要代理的對象太多,Spring.Net  幫我們提供了通配符的匹配方式,如:"*name","name*",”*name*“和精確文本如"name"。而且還提供了正則表達式的匹配方式,這里就不舉例了-->
25         <value>car*</value>
26       </list>
27     </property>
28     <!--AOP代理對象中,使用的通知實例-->
29     <property name="InterceptorNames">
30       <list>
31         <value>aroundAdvice</value>
32         <value>beforeAdvice</value>
33         <value>afterReturningAdvice</value>
34         <value>throwsAdvice</value>
35       </list>
36     </property>
37     
38   </object>
39   
40 </objects>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM