zoukankan      html  css  js  c++  java
  • 第五章 面向方面编程___通知类型

      前面两节谈到了 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>
  • 相关阅读:
    Angular随笔第一课
    web前端面试集锦(自己搜集的,如有错误请不吝赐教)
    菜单选项卡-2中方法加载选项卡的内容
    dialog使用方法(同一页面,调用一个js代码,实现多个不同样式的弹窗)
    JAVA中对象赋值以及前拷贝,深拷贝等~~
    基类指针指向派生类对象
    JAVA中方法的参数传递(转)
    java和C++的const 和 final 的区别
    JAVA--虚函数,抽象函数,抽象类,接口
    libdash编译中遇到的问题及解决方案
  • 原文地址:https://www.cnblogs.com/hexu6788/p/2980690.html
Copyright © 2011-2022 走看看