zoukankan      html  css  js  c++  java
  • Spring.NET教程(十二)——AOP的通知类型(基础篇)

    上篇我们学习了AOP的基本概念,我们回顾一下上篇提到的Advice(通知):所谓通知是指拦截到joinpoint(连接点)之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,环绕通知。

      Spring.NET的通知既可由某个类的所有对象共享,也可由该类型的单个实例独占。共享的通知称为基于类型(per-class)的通知,而独占的通知称为基于实例(per-instance)的通知。

      基于类型的通知最为常用。很多常用功能很适合用基于类型的通知实现,比如说事务。它们不依赖于目标对象的状态,也不会向目标对象添加新状态,仅仅对方法及其参数进行操作。

      基于实例的通知比较适合做引入(introductions)。此时通知可以向目标对象添加状态。在AOP代理中,可以同时使用基于类型和基于实例的通知。Spring.NET和spring框架略有不同,只有四种通知类型,没有spring框架的最终通知(目前我还没有实现最终通知,如果有朋友实现的话,可以给我留言)。

      一、拦截环绕通知(around advice):Spring.NET中最基本的通知类型是拦截环绕通知(interception around advice),即方法拦截器。拦截环绕通知继承IMethodInterceptor接口。注意其中IMethodInvocation.Proceed()方法的调用。该方法会依次调用拦截器链上的其它拦截器。大部分拦截器都需要调用这个方法并返回它的返回值。当然,也可以不调用Proceed方法,而返回一个其它值或抛出一个异常,但一般不太会这么做。

      二、前置通知(before advise):是在IMethodInterceptor.Proceed()方法调用前的通知。继承自IMethodBeforeAdvice接口。

      三、异常通知(throws advise):是在IMethodInterceptor.Proceed()方法调用时发生异常的通知。继承自IthrowsAdvice接口。IthrowsAdvice接口没有定义任何方法:它是一个标识接口(按:之所以用标识接口,原因有二:1、在通知方法中,只有最后一个参数是必须的。如果声明为接口的方法,参数列表就被固定了。2、如果第一个原因可以用重载的接口方法解决,那么这个原因就是使用标识接口的充分原因了:实现此接口的类必须声明一或多个通知方法,接口方法做不到这一点),用以表明实现它的类声明了一或多个强类型的异常通知方法。

     四、后置通知(after returning advise):是在IMethodInterceptor.Proceed()方法调用后的通知。继承自IAfterReturningAdvice接口。后置通知对切入点的执行没有影响,如果通知抛出异常,就会沿拦截器链向上抛出,从而中断拦截器链的继续执行。

      代码实现:

      准备条件

      四种通知:

      AroundAdvise

        /**//// <summary>
        /// 环绕通知
        /// </summary>
        public class AroundAdvise : IMethodInterceptor
        {
            public object Invoke(IMethodInvocation invocation)
            {
                Console.Out.WriteLine(string.Format(" 环绕通知: 调用的方法 '{0}'", invocation.Method.Name));
                Console.WriteLine();
                object returnValue = null;
                try 
                {
                    returnValue = invocation.Proceed();
                }
                catch
                {
                    Console.Out.WriteLine(" 环绕通知: 发生异常");
                    Console.WriteLine();
                }
                Console.Out.WriteLine(String.Format(" 环绕通知: 返回值 '{0}'", returnValue));
                return returnValue;
            }
        }

    BeforeAdvise

        /**//// <summary>
        /// 前置通知
        /// </summary>
        public class BeforeAdvise : IMethodBeforeAdvice
        {
            public void Before(MethodInfo method, object[] args, object target)
            {
                Console.Out.WriteLine("     前置通知: 调用的方法名 : " + method.Name);
                Console.Out.WriteLine("     前置通知: 目标       : " + target);
                Console.Out.WriteLine("     前置通知: 参数为   : ");
                if (args != null)
                {
                    foreach (object arg in args)
                    {
                        Console.Out.WriteLine("\t: " + arg);
                    }
                }
                Console.WriteLine();
            }
        }

      ThrowsAdvise

        /**//// <summary>
        /// 异常通知
        /// </summary>
        public class ThrowsAdvise : IThrowsAdvice 
        {
            public void AfterThrowing(Exception ex)
            {
                string errorMsg = string.Format("     异常通知: 方法抛出的异常 : {0}", ex.Message);
                Console.Error.WriteLine(errorMsg);
                Console.WriteLine();
            }
        }

    AfterReturningAdvise

        /**//// <summary>
        /// 后置通知
        /// </summary>
        public class AfterReturningAdvise : IAfterReturningAdvice
        {
            public void AfterReturning(object returnValue, MethodInfo method, object[] args, object target)
            {
                Console.Out.WriteLine("     后置通知: 方法调用成功,方法名 : " + method.Name);
                Console.Out.WriteLine("     后置通知: 目标为      : " + target);
                Console.Out.WriteLine("     后置通知: 参数 : ");
                if (args != null)
                {
                    foreach (object arg in args)
                    {
                        Console.Out.WriteLine("\t: " + arg);
                    }
                }
                Console.Out.WriteLine("     后置通知:  返回值是 : " + returnValue);
                Console.WriteLine();
            }
        }

      接口:

        public interface IOrderService
        {
            object Save(object id);
        }

      一、没有异常的情况

    OrderService

        public class OrderService : IOrderService
        {
            /**//// <summary>
            /// 拦截该方法
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public object Save(object id)
            {
                //throw new Exception("由于XXX原因保存出错");  
                return "保存:" + id.ToString();
            }
        }

      Program

        class Program
        {
            static void Main(string[] args)
            {
                ProxyFactory factory = new ProxyFactory(new OrderService());
                factory.AddAdvice(new AroundAdvise());
                factory.AddAdvice(new BeforeAdvise());
                factory.AddAdvice(new AfterReturningAdvise());
                factory.AddAdvice(new ThrowsAdvise());
                IOrderService service = (IOrderService)factory.GetProxy();
                object result = service.Save(1);
                Console.WriteLine();
                Console.WriteLine(string.Format("客户端返回值:{0}", result));
                
                Console.ReadLine();
            }
        }

    输出效果:见图1

    Spring.NET教程(十四)——AOP的通知类型(基础篇) Level 300

      图1

      二、有异常的情况:

      OrderService

    public class OrderService : IOrderService
        {
            /**//// <summary>
            /// 拦截该方法
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public object Save(object id)
            {
                throw new Exception("由于XXX原因保存出错");  
                //return "保存:" + id.ToString();
            }
        }

      输出效果:见图2

    Spring.NET教程(十四)——AOP的通知类型(基础篇) Level 300

      图2

      从图与代码中,我们不难看出Advice(通知)的生命周期。拦截环绕通知(around advice)围绕着整个拦截过程;前置通知(before advise)在方法调用前执行;异常通知(throws advise)在调用方法时发生异常才执行,否则不执行;后置通知(after returning advise)在方法调用后执行,当调用时出现异常,则不执行后置通知(after returning advise)。

  • 相关阅读:
    Linux内核网络协议栈优化总纲
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 链表数据求和操作
  • 原文地址:https://www.cnblogs.com/millen/p/1635967.html
Copyright © 2011-2022 走看看