• AOP面向切面编程(一)


    本章将简单介绍下AOP面向切面编程。首先我们先来看些概念。

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

    OOP面向对象编程

      万物皆对象,对象交互完成功能,功能叠加成模块,模块组成系统,去搭建复杂的大型软件系统。

      类却是会变化的,增加日志/异常/权限/缓存/事务,只能修改类?

      只能替换整个对象,没办法把一个类动态改变。

      GOF的23种设计模式,应对变化,核心套路是依赖抽象,细节就可以变化。

    AOP面向切面编程

      是一种编程思想,是OOP思想的补充。

      允许开发者动态的修改静态的OO模型,就像现实生活中对象在生命周期中会不断的改变自身。    

      正是因为能够动态的扩展功能,所以在程序设计时就可以有以下好处:

        1、只需要聚焦核心业务逻辑,权限/异常/日志/缓存/事务等通用功能可以通过AOP方式添加,使程序设计变得更加简单。

        2、功能动态扩展;集中管理;代码复用;规范化;

      实现AOP的多种方式:

        1、静态实现---装饰器模式/代理模式。

        2、动态实现---Remoting/Castle(Emit)

        3、静态织入---PostSharp(收费)---扩展编译工具,生成的加入额外代码。

        4、依赖注入容器的AOP扩展(开发)

        5、MVC的Filter---特性标记,然后该方法执行前/后就多了逻辑。

    下面看一张图来辅助我们了解:

    从图中一刀切过去将核心业务逻辑和我们的通用功能分离,这样的话我们只需要聚焦核心业务逻辑,而权限/异常/日志/缓存/事务等通用功能可以通过AOP方式添加,使程序设计变得更加简单。

    下面我们重点来看下代码如何实现,为了演示此处我们使用VS2017建个控制台项目MyAOP,目标框架为:.NET Framework 4.6.1,如下所示:

    一、代理模式实现静态代理(静态实现AOP)

    using System;
    
    namespace MyAOP
    {
        /// <summary>
        /// 用户类
        /// </summary>
        public class User
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Password { get; set; }
        }
    }
    using System;
    
    namespace MyAOP
    {
        /// <summary>
        /// 代理模式实现静态代理
        /// AOP 在方法前后增加自定义的方法
        /// </summary>
        public class ProxyAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "浪子天涯",
                    Password = "123456"
                };
                IUserProcessor processor = new UserProcessor();
                processor.RegUser(user);
    
                Console.WriteLine("***************");
    
                processor = new ProxyUserProcessor();
                processor.RegUser(user);
            }
    
            public interface IUserProcessor
            {
                void RegUser(User user);
            }
    
            public class UserProcessor : IUserProcessor
            {
                public void RegUser(User user)
                {
                    Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
                }
            }
    
            /// <summary>
            /// 代理模式去提供一个AOP功能
            /// </summary>
            public class ProxyUserProcessor : IUserProcessor
            {
                private IUserProcessor _userProcessor = new UserProcessor();
                public void RegUser(User user)
                {
                    BeforeProceed(user);
                    this._userProcessor.RegUser(user);
                    AfterProceed(user);
                }
    
                /// <summary>
                /// 业务逻辑之前
                /// </summary>
                private void BeforeProceed(User user)
                {
                    Console.WriteLine("方法执行前");
                }
    
                /// <summary>
                /// 业务逻辑之后
                /// </summary>
                private void AfterProceed(User user)
                {
                    Console.WriteLine("方法执行后");
                }
            }
        }
    }

    看下调用ProxyAOP.Show()的结果:

    二、装饰器模式实现静态代理(静态实现AOP)

    using System;
    
    namespace MyAOP
    {
        /// <summary>
        /// 装饰器模式实现静态代理
        /// AOP 在方法前后增加自定义的方法
        /// </summary>
        public class DecoratorAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "浪子天涯",
                    Password = "88888888"
                };
    
                IUserProcessor processor = new UserProcessor();
                processor.RegUser(user);
    
                Console.WriteLine("***************");
    
                processor = new UserProcessorDecorator(processor);
                processor.RegUser(user);
            }
    
            public interface IUserProcessor
            {
                void RegUser(User user);
            }
    
            public class UserProcessor : IUserProcessor
            {
                public void RegUser(User user)
                {
                    Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
                }
            }
    
            /// <summary>
            /// 装饰器模式去提供一个AOP功能
            /// </summary>
            public class UserProcessorDecorator : IUserProcessor
            {
                private IUserProcessor _userProcessor { get; set; }
                public UserProcessorDecorator(IUserProcessor userprocessor)
                {
                    this._userProcessor = userprocessor;
                }
    
                public void RegUser(User user)
                {
                    BeforeProceed(user);
    
                    this._userProcessor.RegUser(user);
    
                    AfterProceed(user);
                }
    
                /// <summary>
                /// 业务逻辑之前
                /// </summary>
                private void BeforeProceed(User user)
                {
                    Console.WriteLine("方法执行前");
                }
    
                /// <summary>
                /// 业务逻辑之后
                /// </summary>
                private void AfterProceed(User user)
                {
                    Console.WriteLine("方法执行后");
                }
            }
        }
    }

    看下调用DecoratorAOP.Show()的结果:

    3、使用Unity容器实现AOP

    首先来看下项目的目录结构:

    需要从NuGet上安装如下程序包:

    核心业务逻辑:

    using System;
    
    namespace MyAOP.UnityWay
    {
        public interface IUserProcessor
        {
            //[Obsolete] //此处可扩展
            void RegUser(User user);
            User GetUser(User user);
        }
    }
    using System;
    
    namespace MyAOP.UnityWay
    {
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用户已注册。");
            }
    
            public User GetUser(User user)
            {
                return user;
            }
        }
    }

    AOP扩展:

    using System;
    using System.Collections.Generic;
    using Unity.Interception.InterceptionBehaviors;
    using Unity.Interception.PolicyInjection.Pipeline;
    
    namespace MyAOP.UnityWay
    {
        /// <summary>
        /// 缓存AOP扩展
        /// </summary>
        public class CachingBehavior : IInterceptionBehavior
        {
            /// <summary>
            /// 固定写法
            /// </summary>
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("CachingBehavior");
                //input.Target.GetType().GetCustomAttributes()
                if (input.MethodBase.Name.Equals("GetUser"))
                    return input.CreateMethodReturn(new User() { Id = 234, Name = "Eleven" });
                return getNext().Invoke(input, getNext);
            }
    
            /// <summary>
            /// 固定写法
            /// </summary>
            public bool WillExecute
            {
                get { return true; }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using Unity.Interception.InterceptionBehaviors;
    using Unity.Interception.PolicyInjection.Pipeline;
    
    namespace MyAOP.UnityWay
    {
        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; }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using Unity.Interception.InterceptionBehaviors;
    using Unity.Interception.PolicyInjection.Pipeline;
    
    namespace MyAOP.UnityWay
    {
        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; }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using Unity.Interception.InterceptionBehaviors;
    using Unity.Interception.PolicyInjection.Pipeline;
    
    namespace MyAOP.UnityWay
    {
        /// <summary>
        /// 不需要特性
        /// </summary>
        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; }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using Unity.Interception.InterceptionBehaviors;
    using Unity.Interception.PolicyInjection.Pipeline;
    
    namespace MyAOP.UnityWay
    {
        /// <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; }
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using Unity.Interception.InterceptionBehaviors;
    using Unity.Interception.PolicyInjection.Pipeline;
    
    namespace MyAOP.UnityWay
    {
        public class ParameterCheckBehavior : IInterceptionBehavior
        {
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                Console.WriteLine("ParameterCheckBehavior");
                User user = input.Inputs[0] as User;
                if (user.Password.Length < 10)
                {
                    return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
                }
                else
                {
                    Console.WriteLine("参数检测无误");
                    return getNext().Invoke(input, getNext);
                }
            }
    
            public bool WillExecute
            {
                get { return true; }
            }
        }
    }

    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="aopContainer">
            <extension type="Interception"/>
            <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP">
              <interceptor type="InterfaceInterceptor"/>
              <interceptionBehavior type="MyAOP.UnityWay.MonitorBehavior, MyAOP"/>
    
              <interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/>
              <interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/>
    
            </register>
          </container>
        </containers>
      </unity>
    </configuration>

    注意:编译时需要将配置文件输出到bin/debug目录下,设置如下所示:

    使用如下:

    using System;
    using System.IO;
    using System.Configuration;
    using Microsoft.Practices.Unity.Configuration;
    using Unity;
    
    namespace MyAOP.UnityWay
    {
        public class UnityConfigAOP
        {
            public static void Show()
            {
                User user = new User()
                {
                    Name = "浪子天涯",
                    Password = "12345678910"
                };
                //配置UnityContainer
                IUnityContainer container = new UnityContainer();
                ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
                fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\Unity.config");
                Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
    
                UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
                configSection.Configure(container, "aopContainer");
    
                IUserProcessor processor = container.Resolve<IUserProcessor>();
                processor.RegUser(user);
                processor.GetUser(user);
            }
        }
    }

    调用UnityConfigAOP.Show()的结果如下:

    可以发现执行顺序就像俄罗斯套娃,如下所示:

    Demo源码:

    链接:https://pan.baidu.com/s/147Veb1fU49sT5bcEbgrERw 
    提取码:j5ml

    此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13532063.html    

    版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

  • 相关阅读:
    悲观锁、乐观锁、行级锁、表级锁
    MySQL中锁详解(行锁、表锁、页锁、悲观锁、乐观锁等)
    刷题-力扣-148. 排序链表
    刷题-力扣-206. 反转链表
    刷题-力扣-203. 移除链表元素
    刷题-力扣-474. 一和零
    刷题-力扣-494. 目标和
    刷题-力扣-160. 相交链表
    刷题-力扣-34. 在排序数组中查找元素的第一个和最后一个位置
    刷题-力扣-33. 搜索旋转排序数组
  • 原文地址:https://www.cnblogs.com/xyh9039/p/13532063.html
Copyright © 2020-2023  润新知