• Spring.Net AOP的通知类型及通知链


      首先介绍AOP通知的概念。

      通知(Advice):AOP框架在某个连接点(方法)中所采取的行为。在Spring.Net的通知类型分为环绕通知、前置通知、后置通知、异常通知。这四中通知类型以及这几通知综合运用形成的通知链。

      关于各种通知类型我实现的编程方式、配置方式两种给大家介绍。这一节主要说说上述通知类型中的后三种通知,前一种通知在上一节中已经做了说明,所以不作为本节的重点了,但是几种通知的应用大致是一样的。

      本节重点分如下两部分:

      一、AOP的四种通知类型。

      二、通知链的应用

      首先还是介绍一下开发环境以及软件版本:

      VS版本:VS2008 SP1、Spring版本:1.3.0。

      一、AOP四种通知类型介绍

      1、前置通知。我理解的前置通知是在目标对象连接点执行前的通知。

      编程方式实现。这种方式主要应用了程序集Spring.Net中Spring.Aop.Framework命名空间下的ProxyFactory(代理工厂)类和Spring.Aop命名控件下的IMethodBeforeAdvice接口。

    目标对象的代码如下:  

    代码
    1 public interface ICommand
    2 {
    3 void Execute();
    4 }
    5
    6 class ServiceCommand:ICommand
    7 {
    8 public void Execute()
    9 {
    10 Console.WriteLine("ServiceCommand execute");
    11 }
    12 }

    通知的实现代码:

    代码
    1 class ConsoleLoggingBeforeAdvice:IMethodBeforeAdvice
    2 {
    3 public void Before(MethodInfo method, object[] args, object target)
    4 {
    5 Console.WriteLine("Method name is :{0}", method.Name);
    6 if (args != null)
    7 {
    8 if (args.Length > 0)
    9 {
    10 for (int i = 0; i < args.Length; i++)
    11 {
    12 Console.WriteLine(" the {0} position argments in args is {1}", i, args[i]);
    13 }
    14 }
    15 }
    16 else
    17 {
    18 Console.WriteLine("args is null");
    19 }
    20 Console.WriteLine("the type target is {0}",target.GetType().ToString());
    21 }
    22 }

    实现代码如下:

    代码
    1 ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    2 factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
    3 ICommand command = (ICommand)factory.GetProxy();
    4 command.Execute();

    运行结果图如下:

      配置方式实现。配置代码如下:

    代码
    1 <objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
    2 <object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
    3 <property name="Target">
    4 <object type="SpringBeforeAdvice.ServiceCommand" singleton="0"></object>
    5 </property>
    6 <property name="InterceptorNames">
    7 <list>
    8 <value>beforeAdvice</value>
    9 </list>
    10 </property>
    11 </object>
    12 <object id="beforeAdvice" type="SpringBeforeAdvice.ConsoleLoggingBeforeAdvice"></object>
    13 </objects>

    实现代码如下:

    代码
    1 IApplicationContext context = ContextRegistry.GetContext();
    2 ICommand command2 = (ICommand)context["myServiceObject"];
    3 command2.Execute();
    4 IDictionary dic = context.GetObjectsOfType(typeof(ICommand));
    5 foreach (DictionaryEntry item in dic)
    6 {
    7 Console.WriteLine("key is :{0},value is :{1}", item.Key, item.Value);
    8 }

    运行结果如下图:

    可以看到:出了运行连接点Execute执行运行的代码以外,还有通知采取的行为(Before的执行)。如果通过断点调试,可以看到在连接点执行前,Before执行了。

      2、后置通知。后置通知正好是前置通知相反,是在目标对象连接点执行后的通知。它是实现了Spring.Aop命名空间下的IAfterReturningAdvice接口。

      编程方式实现。

      目标对象的实现代码和前置通知实现方式相同,这里就不给出实现代码了。后置通知的实现代码是:

    代码
    1 class ConsoleLoggingAfterAdvice: IAfterReturningAdvice
    2 {
    3 public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
    4 {
    5 if (returnValue != null)
    6 {
    7 Console.WriteLine("the type of returnValue is :{0},returnValue is {1}", returnValue.GetType().ToString(), returnValue);
    8 }
    9 Console.WriteLine("method name is {0}", method.Name);
    10 if (args != null && args.Length > 0)
    11 {
    12 foreach (object obj in args)
    13 {
    14 Console.WriteLine(obj);
    15 }
    16 }
    17 Console.WriteLine("the type of target is :{0},returnValue is {1}", target.GetType().ToString(), target);
    18 }
    19 }

    使用代码:

    代码
    1 ICommand target = new ServiceCommand();
    2 ProxyFactory factory = new ProxyFactory(target);
    3 factory.AddAdvice(new ConsoleLoggingAfterAdvice());
    4
    5 ICommand command = (ICommand)factory.GetProxy();
    6 command.Execute("test string");

    运行结果如下图:

      配置方式实现。配置文件如下:

    代码
    1 <objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
    2
    3 <object id ="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject" >
    4 <property name="Target">
    5 <object type="SpringAfterAdvice.ServiceCommand"></object>
    6 </property>
    7 <property name="InterceptorNames">
    8 <list>
    9 <value>afterAdvice</value>
    10 </list>
    11 </property>
    12 </object>
    13
    14 <object id="afterAdvice" type="SpringAfterAdvice.ConsoleLoggingAfterAdvice" ></object>
    15 </objects>

    实现代码:

    1 IApplicationContext context = ContextRegistry.GetContext();
    2 ICommand command2 = (ICommand)context["myServiceObject"];
    3 command2.Execute("config string");

    运行结果如下图:

      与前置通知相反,后置通知在目标对象连接点执行后再执行。

      3、异常通知。我理解的是当目标对象的连接点执行出现异常的时候执行。异常通知是实现了Spring.Aop命名空间下的IThrowingAdvice接口。

      编程方式实现:

      异常通知实现代码如下:
     

    代码
    1 public void AfterThrowing(FormatException ex)
    2 {
    3 Console.WriteLine("异常通知执行");
    4 Console.WriteLine(ex.Message);
    5 }
    6
    7
    8 public void AfterThrowing(UnauthorizedAccessException ex)
    9 {
    10 Console.Out.WriteLine("Advised method threw this exception : " + ex);
    11 }

      使用代码如下:

    代码
    1 ICommand target = new ServiceCommand();
    2 ProxyFactory factory = new ProxyFactory(target);
    3 factory.AddAdvice(new AroudAdvice());
    4 factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
    5
    6 ICommand command = (ICommand)factory.GetProxy();
    7 command.Execute();

     


      配置方式实现。配置文件如下:

    代码
    1 <objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
    2
    3 <object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
    4 <property name="Target">
    5 <object type="SpringExceptionAdvice.ServiceCommand"></object>
    6 </property>
    7 <property name="InterceptorNames">
    8 <list>
    9 <value>aroundAdvice</value>
    10 <value>exceptionAdvice</value>
    11 </list>
    12 </property>
    13 </object>
    14
    15 <object id="exceptionAdvice" type="SpringExceptionAdvice.ConsoleLoggingThrowsAdvice"></object>
    16 <object id="aroundAdvice" type="SpringExceptionAdvice.AroudAdvice"></object>
    17 </objects>
    使用代码如下:

    1 IApplicationContext context = ContextRegistry.GetContext();
    2 ICommand command2 = (ICommand)context["myServiceObject"];
    3 command2.Execute();
    运行结果如下图:

      注意:异常通知实现的IThrowsAdvice中没有任何方法。但是它的实现类中必须实现public void AfterThrowing方法。并且只有目标对象的连接点执行过程中发生异常类型与AfterThrowing方法的参数一样时,异常通知才会发生。当然,AfterThrowing可以有很多重载。

      二、通知链

      1、编程方式实现。各种通知的实现代码如下:

    代码
    1 //前置通知
    2   class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
    3 {
    4 public void Before(MethodInfo method, object[] args, object target)
    5 {
    6 Console.WriteLine("前置通知执行");
    7 Console.WriteLine("method name is {0}",method.Name);
    8 if (args != null)
    9 {
    10 for (int i = 0; i < args.Length; i++)
    11 {
    12 Console.WriteLine(" the {0} position args is :{1}", i, args[i]);
    13 }
    14 }
    15 Console.WriteLine("type of target is :{0}", target.GetType().ToString());
    16
    17 }
    18 }
    19
    20  //环绕通知
    21   class ConsoleLoggingAroundAdvice:IMethodInterceptor
    22 {
    23 public object Invoke(IMethodInvocation invocation)
    24 {
    25 object obj = null;
    26 Console.WriteLine("环绕通知执行");
    27 try
    28 {
    29 obj = invocation.Proceed();
    30 }
    31 catch
    32 {
    33 Console.WriteLine("目标方法执行异常");
    34 }
    35 return obj;
    36 }
    37 }
    38
    39 //后置通知
    40   class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
    41 {
    42 public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
    43 {
    44 Console.WriteLine("后置通知执行");
    45 if (returnValue != null)
    46 {
    47 Console.WriteLine("returnValue is :{0}",returnValue);
    48 }
    49 Console.WriteLine("method name is :{0}", method.Name);
    50 if (args != null)
    51 {
    52 for (int i = 0; i < args.Length; i++)
    53 {
    54 Console.WriteLine(" the {0} position args is :{1}",i,args[i]);
    55 }
    56 }
    57 Console.WriteLine("type of target is :{0}",target.GetType().ToString());
    58
    59 }
    60 }
    61
    62  //异常通知
    63   class ConsoleLoggingThrowsAdvice:IThrowsAdvice
    64 {
    65 public void AfterThrowing(FormatException ex)
    66 {
    67 Console.WriteLine("发生异常通知");
    68 Console.WriteLine(ex.Message);
    69 }
    70 }
    使用代码如下:

    代码
    1 ProxyFactory factory = new ProxyFactory(new ServiceCommand());
    2
    3 factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
    4 factory.AddAdvice(new ConsoleLoggingAroundAdvice());
    5 factory.AddAdvice(new ConsoleLoggingAfterAdvice());
    6 factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
    7
    8 ICommand command = (ICommand)factory.GetProxy();
    9 command.Execute("spring advice link ---programming");
    运行结果如下:

      注意织入方式,即factory.AddAdvice添加通知的顺序。我个人感觉应该按照前置--环绕--后置的方式来进行织入。如果我改成

        factory.AddAdvice(new ConsoleLoggingAroundAdvice());
                factory.AddAdvice(new ConsoleLoggingAfterAdvice());
                factory.AddAdvice(new ConsoleLoggingBeforeAdvice());

    则运行结果如下图:

      2、配置方式实现

      配置文件如下:

    代码
    1 <objects xmlns="http://www.springframework.net" xmlns:aop="http://www.springframework.net/aop">
    2 <object id="myServiceObj" type="Spring.Aop.Framework.ProxyFactoryObject,Spring.Aop">
    3 <property name="Target">
    4 <object id="serviceCommand" type="SpringAdviceLink.ServiceCommand"></object>
    5 </property>
    6 <property name="InterceptorNames">
    7 <list>
    8 <value>beforAdvice</value>
    9 <value>aroundAdvice</value>
    10 <value>afterAdvice</value>
    11 <value>exceptionAdvice</value>
    12 </list>
    13 </property>
    14 </object>
    15
    16 <object id="beforAdvice" type="SpringAdviceLink.ConsoleLoggingBeforeAdvice"></object>
    17 <object id="aroundAdvice" type="SpringAdviceLink.ConsoleLoggingAroundAdvice"></object>
    18 <object id="afterAdvice" type="SpringAdviceLink.ConsoleLoggingAfterAdvice"></object>
    19 <object id="exceptionAdvice" type="SpringAdviceLink.ConsoleLoggingThrowsAdvice"></object>
    使用方式如下:

    1 IApplicationContext context = ContextRegistry.GetContext();
    2 ICommand command2 = (ICommand)context["myServiceObj"];
    3 command2.Execute("spring advice link ---config");
    运行结果如下图:

      在配置方式实现中,也要注意<property name="InterceptorNames"/>中list列表中的中值的顺序,顺序不一样执行的结果也不一样。我个人觉得应该是前置--环绕--后置的方式进行配置,至于异常通知的配置由于是连接点执行异常时才执行,所以它的为位置关系不重要。

      总结:环绕通知实现的是AopAlliance.Intercept命名控件下的IMethodInterceptor接口前置通知、后置通知、异常通知分别实现的是Spring.Aop命名空间下的IMethodBeforeAdvice、IAfterReturningAdvice、IThrowsAdvice接口.IThrowsAdvice的实现类必须有AfterThrowing方法,并且AfterThrowing可以有各种异常类型作为参数的重载。

      参考文档Spring.Net参考框架.

      代码下载:代码Demo

  • 相关阅读:
    【HDU3681】Prison Break-状态压缩DP+BFS+二分答案
    【BashuOJ3520】警察局长-最短路树+树上背包+概率DP
    【POJ1201】Intervals-差分约束系统+单源最长路
    【BashuOJ2041】最大矩形-矩阵型DP
    【BashuOJ2041】最大矩形-矩阵型DP
    deleted
    deleted
    deleted
    deleted
    deleted
  • 原文地址:https://www.cnblogs.com/tyb1222/p/1904327.html
Copyright © 2020-2023  润新知