zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/tyb1222/p/1904327.html
Copyright © 2011-2022 走看看