C# 面向切面编程 AOP

AOP(Aspect Oriented Programming) 面向切面编程

起源

引言  http://wayfarer.cnblogs.com/articles/241012.html

AOP技术基础  https://www.cnblogs.com/wayfarer/articles/241024.html

.Net平台AOP技术研究 https://www.cnblogs.com/wayfarer/articles/256909.html

AOP、POP、OOP 区别与联系

POP面向过程编程:符合逻辑思维,线性的处理问题-----无法应付复杂的系统

OOP面向对象编程:万物皆对象,对象交互完成功能,功能叠加成模块,模块组成系统,去搭建复杂的大型软件系统
 类----功能点---模块----系统 
 类却是会变化的,增加日志/异常/权限/缓存/事务,只能修改类?
 GOF的23种设计模式,应对变化,核心套路是依赖抽象,细节就可以变化
 但是只能替换整个对象,但是没办法把一个类动态改变

AOP(Aspect):允许开发者动态的修改静态的OO模型,就像现实生活中对象在生命周期中会不断的改变自身。 
AOP是一种编程思想,是OOP思想的补充

正是因为能够动态的扩展功能,所以在程序设计时就可以有以下好处:
1 聚焦核心业务逻辑,权限/异常/日志/缓存/事务, 通用功能可以通过AOP方式添加,程序设计简单,
2 功能动态扩展;集中管理,代码复用;规范化;

实现AOP的多种方式
a 静态实现--装饰器/代理模式
b 动态实现--Remoting/Castle(Emit)
c 静态织入--PostSharp(收费)--扩展编译工具,生成的加入额外代码
d 依赖注入容器的AOP扩展(开发)
e MVC的Filter--特性标记,然后该方法执行前/后就多了逻辑  invoker调用中心--负责反射调用方法--检查特性--有则执行额外逻辑 

A 装饰器模式实现静态代理-AOP 在方法前后增加自定义的方法

    public class Business : IBusiness
    {
        public virtual void DoSomething()
        {
            Console.WriteLine("DoSomething");
        }
    }
    public class BusinessAOP : IBusiness
    {
        public BusinessAOP(IBusiness IBusiness)
        {
            this._IBusiness = IBusiness;
        }
        private IBusiness _IBusiness;
        public override void DoSomething()
        {
            BeforeProceed();
            this._IBusiness.DoSomething();
            AfterProceed();
        }
        /// <summary>
        /// 业务逻辑之前
        /// </summary>
        /// <param name="user"></param>
        private void BeforeProceed()
        {
            Console.WriteLine("方法执行前");
        }
        /// <summary>
        /// 业务逻辑之后
        /// </summary>
        /// <param name="user"></param>
        private void AfterProceed()
        {
            Console.WriteLine("方法执行后");
        }
    }
    public interface IBusiness
    {
        void DoSomething();
    }
      //前端调用
      new BusinessAOP(new Business()).DoSomething();

 代理模式实现静态代理-AOP 在方法前后增加自定义的方法

public class Business : IBusiness
    {
        public void DoSomething()
        {
            Console.WriteLine("DoSomething");
        }
    }
    public class ProxyBusinessAOP : IBusiness
    {
        private IBusiness _IBusiness=new Business();
        public void DoSomething()
        {
            BeforeProceed();
            this._IBusiness.DoSomething();
            AfterProceed();
        }
        /// <summary>
        /// 业务逻辑之前
        /// </summary>
        /// <param name="user"></param>
        private void BeforeProceed()
        {
            Console.WriteLine("方法执行前");
        }
        /// <summary>
        /// 业务逻辑之后
        /// </summary>
        /// <param name="user"></param>
        private void AfterProceed()
        {
            Console.WriteLine("方法执行后");
        }
    }
    public interface IBusiness
    {
        void DoSomething();
    }
    //前端调用
    new ProxyBusinessAOP().DoSomething();

B 使用.Net Remoting下的RealProxy 实现动态代理-局限在业务类必须是继承自MarshalByRefObject类型

/// <summary>
    /// 必须继承自MarshalByRefObject父类,否则无法生成
    /// </summary>
    public class Business : MarshalByRefObject, IBusiness
    {
        public void DoSomething()
        {
            Console.WriteLine("DoSomething");
        }
    }
    /// <summary>
    /// 真实代理
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class MyRealProxy<T> : RealProxy
    {
        private T tTarget;
        public MyRealProxy(T target)
            : base(typeof(T))
        {
            this.tTarget = target;
        }

        public override IMessage Invoke(IMessage msg)
        {
            BeforeProceede(msg);//Log  try-catch

            IMethodCallMessage callMessage = (IMethodCallMessage)msg;
            object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args);

            AfterProceede(msg);

            return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
        }
        public void BeforeProceede(IMessage msg)
        {
            Console.WriteLine("方法执行前可以加入的逻辑");
        }
        public void AfterProceede(IMessage msg)
        {
            Console.WriteLine("方法执行后可以加入的逻辑");
        }
    }
    /// <summary>
    /// 透明代理
    /// </summary>
    public static class TransparentProxy
    {
        public static T Create<T>()
        {
            T instance = Activator.CreateInstance<T>();
            MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
            T transparentProxy = (T)realProxy.GetTransparentProxy();
            return transparentProxy;
        }
    }
    
    public interface IBusiness
    {
        void DoSomething();
    }
     //前端调用
     IBusiness iBusiness = new Business();
     iBusiness.DoSomething();
     Console.WriteLine("*********************");
     iBusiness = TransparentProxy.Create<Business>();
     iBusiness.DoSomething();

B  使用Castle\DynamicProxy 实现动态代理-方法必须是虚方法

/// <summary>
    /// 使用Castle\DynamicProxy 实现动态代理
    /// 方法必须是虚方法
    /// </summary>
    public class CastleProxyAOP
    {
        public static void Show()
        {
            
            ProxyGenerator generator = new ProxyGenerator();
            MyInterceptor interceptor = new MyInterceptor();
            Business bus = generator.CreateClassProxy<Business>(interceptor);
            bus.DoSomething();
            Console.Read();
        }
        public interface IBusiness
        {
            void DoSomething();
        }

        public class Business : IBusiness
        {
            /// <summary>
            /// 必须带上virtual 否则无效~
            /// </summary>
            /// <param name="user"></param>
            public virtual void DoSomething()
            {
                Console.WriteLine("DoSomething");
            }
        }

        public class MyInterceptor : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                PreProceed(invocation);
                invocation.Proceed();//就是调用原始业务方法
                PostProceed(invocation);
            }
            public void PreProceed(IInvocation invocation)
            {
                Console.WriteLine("方法执行前");
            }

            public void PostProceed(IInvocation invocation)
            {
                Console.WriteLine("方法执行后");
            }
        }
    }

 使用EntLib\PIAB Unity 实现动态代理

using System;
using Unity;
using Unity.Interception;
using Unity.Interception.Interceptors.InstanceInterceptors.InterfaceInterception;
using Unity.Interception.PolicyInjection.Pipeline;
using Unity.Interception.PolicyInjection.Policies;
namespace FrameworkConsole
{
    public class UnityAOP
    {
        public static void Show()
        {
            IUnityContainer container = new UnityContainer();//声明一个容器
            container.RegisterType<IBusiness, Business>();//注册IBusiness
            IBusiness bus = container.Resolve<IBusiness>();//获取 IBusiness 对象
            bus.DoSomething();//调用

            Console.WriteLine("********************");
            container.AddNewExtension<Interception>();
            container.RegisterType<IBusiness, Business>()//注册IBusiness
                .Configure<Interception>()//配置拦截
                .SetInterceptorFor<IBusiness>(new InterfaceInterceptor());//设置拦截器
            bus = container.Resolve<IBusiness>();//重新获取 IBusiness 对象
            bus.DoSomething();//调用
            Console.Read();
        }
        
    }
}

业务层

#region 业务
    [ExceptionHandlerAttribute(Order = 3)]
    [LogHandlerAttribute(Order = 2)]
    [AfterLogHandlerAttribute(Order = 5)]
    public interface IBusiness
    {
        void DoSomething();
    }

    public class Business : IBusiness
    {
        public void DoSomething()
        {
            Console.WriteLine("DoSomething");
        }
    }
    #endregion 业务
    /*
    
    InterfaceInterceptor:在接口的方法上进行标记,这样继承这个接口的类里实现这个接口方法的方法就能被拦截
    */

Unity 扩展特性

#region 特性

    public class LogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LogHandler() { Order = this.Order };
        }
    }

    public class ExceptionHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new ExceptionHandler() { Order = this.Order };
        }
    }

    public class AfterLogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new AfterLogHandler() { Order = this.Order };
        }
    }
    #endregion 特性

特性对应的行为

#region 特性对应的行为

    public class LogHandler : ICallHandler
    {
        public int Order { get; set; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="input">方法调用的参数列表</param>
        /// <param name="getNext"></param>
        /// <returns></returns>
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", "logInfo", DateTime.Now);
            return getNext()(input, getNext);//先记录日志后,执行下一步操作
        }
    }


    public class ExceptionHandler : ICallHandler
    {
        public int Order { get; set; }
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn methodReturn = getNext()(input, getNext);//先执行下一步操作,再回来校验执行结果是否发生异常
            if (methodReturn.Exception == null)
            {
                Console.WriteLine("无异常");
            }
            else
            {
                Console.WriteLine($"异常:{methodReturn.Exception.Message}");
            }
            return methodReturn;
        }
    }

    public class AfterLogHandler : ICallHandler
    {
        public int Order { get; set; }
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn methodReturn = getNext()(input, getNext);//先执行下一步操作,再回来记录完成日志
            Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", "AfterLog", DateTime.Now, methodReturn.ReturnValue);
            return methodReturn;
        }
    }
    #endregion 特性对应的行为

跟踪程序执行过程会发现 程序执行顺序:记录日志=>异常检测=>完成日志=>业务方法=>完成日志=>异常检测

这里程序执行的顺序类似MVC管道模型 典型的俄罗斯套娃模式

把这些业务结合配置文件改成可配置

配置文件Unity.Config

<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
    <!--Microsoft.Practices.Unity.Configuration.UnityConfigurationSection-->
  </configSections>
  <unity>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
    <containers>
      <container name="aop">
        <extension type="Interception"/>
        <register type="FrameworkConsole.IBusiness,FrameworkConsole" mapTo="FrameworkConsole.Business,FrameworkConsole">
          <interceptor type="InterfaceInterceptor"/>
          <interceptionBehavior type="FrameworkConsole.UnityWay.MonitorBehavior, FrameworkConsole"/>

          <interceptionBehavior type="FrameworkConsole.UnityWay.LogBeforeBehavior, FrameworkConsole"/>
          <interceptionBehavior type="FrameworkConsole.UnityWay.ParameterCheckBehavior, FrameworkConsole"/>
          <interceptionBehavior type="FrameworkConsole.UnityWay.CachingBehavior, FrameworkConsole"/>
          <interceptionBehavior type="FrameworkConsole.UnityWay.ExceptionLoggingBehavior, FrameworkConsole"/>
          <interceptionBehavior type="FrameworkConsole.UnityWay.LogAfterBehavior, FrameworkConsole"/>
          
        </register>
      </container>
    </containers>
  </unity>
</configuration>

配置文件配置值 前一项为类地址,后一项为dll地址

另外记得添加Unity.Interception.Configuration.dll

配置行为

public class CachingBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("CachingBehavior");
            return getNext().Invoke(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
public class ExceptionLoggingBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("ExceptionLoggingBehavior");
            IMethodReturn methodReturn = getNext()(input, getNext);
            if (methodReturn.Exception == null)
            {
                Console.WriteLine("无异常");
            }
            else
            {
                Console.WriteLine($"异常:{methodReturn.Exception.Message}");
            }
            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
public class LogAfterBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("LogAfterBehavior");
            foreach (var item in input.Inputs)
            {
                Console.WriteLine(item.ToString());//反射获取更多信息
            }
            IMethodReturn methodReturn = getNext()(input, getNext);
            Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);
            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
public class LogBeforeBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("LogBeforeBehavior");
            foreach (var item in input.Inputs)
            {
                Console.WriteLine(item.ToString());//反射获取更多信息
            }
            return getNext().Invoke(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
/// <summary>
    /// 性能监控的AOP扩展
    /// </summary>
    public class MonitorBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine(this.GetType().Name);
            string methodName = input.MethodBase.Name;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            var methodReturn = getNext().Invoke(input, getNext);//后续逻辑执行

            stopwatch.Stop();
            Console.WriteLine($"{this.GetType().Name}统计方法{methodName}执行耗时{stopwatch.ElapsedMilliseconds}ms");

            return methodReturn;
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }
public class ParameterCheckBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("ParameterCheckBehavior");
            Console.WriteLine("参数检测无误");
            return getNext().Invoke(input, getNext);
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }

调用

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory , "Unity.Config");
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

            UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
            configSection.Configure(container, "aop");

            bus = container.Resolve<IBusiness>();//重新获取 IBusiness 对象
            bus.DoSomething();//调用

序执行顺序(按配置文件顺序执行):监控=>LogBefore=>参数检测=>缓存=>异常检测=>LogAfter=>业务方法=>LogAfter=>异常检测=>监控

微软文档:

System.Configuration https://docs.microsoft.com/zh-cn/dotnet/api/system.configuration?view=netframework-4.8

IUnityContainer https://docs.microsoft.com/zh-cn/previous-versions/msp-n-p/ee649880%28v%3dpandp.10%29

 

 

 

文章出处:https://www.cnblogs.com/Dewumu/p/11766633.html

  

posted @ 2020-03-06 18:19  明志德道  阅读(400)  评论(0编辑  收藏  举报