星星之火

燎原之势不可挡
posts - 127, comments - 374, trackbacks - 0, articles - 3
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

.NET知识梳理——8.AOP

Posted on 2020-03-10 21:43  星星之火116  阅读(...)  评论(...编辑  收藏

1. AOP

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

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

1.1        AOP面向切面编程

1.1.1  AOP有以下好处

1.1.1.1      聚焦核心业务逻辑

权限/异常/日志/缓存/事务等通用功能可以通过AOP方式添加,程序设计简单,

1.1.1.2      功能动态扩展

集中管理,代码复用;规范化;

1.1.2  实现AOP的多种方式

l  静态实现--装饰器/代理模式

l  动态实现--Remoting/Castle(Emit)

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

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

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

invoker调用中心--负责反射调用方法--检查特性--有则执行额外逻辑

1.2        静态AOP实现

静态AOP 可以通过装饰器模式或代理模式进行编码实现。

1.2.1  装饰器模式实现

/// <summary>

    /// 装饰器模式实现静态代理

    /// </summary>

    public class DecoratorAOP

    {

        public static void Show()

        {

            User user = new User()

            {

                Name = "Olive",

                Password = "116"

            };

            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:{user.Name},Password:{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);

            }

 

            private void BeforeProceed(User user)

            {

                Console.WriteLine("方法执行前");

            }

            private void AfterProceed(User user)

            {

                Console.WriteLine("方法执行后");

            }

        }

}

1.2.2  代理模式实现

/// <summary>

    /// 代理模式实现静态代理

    /// AOP在方法前后增加自定义的方法

    /// </summary>

    public class ProxyAOP

    {

        public static void Show()

        {

            User user = new User()

            {

                Name = "XF",

                Password = "1165"

            };

            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:{user.Name},Password:{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);

            }

            private void BeforeProceed(User user)

            {

                Console.WriteLine("方法执行前");

            }

            private void AfterProceed(User user)

            {

                Console.WriteLine("方法执行后");

            }

        }

    }

1.3        动态代理AOP实现

动态AOP可以通过Remoting/Castle(Emit)是实现。

1.3.1  Remoting实现

/// 使用.Net Remoting/RealProxy 实现动态代理

    /// 局限在业务类必须是继承自MarshalByRefObject类型

    public class RealProxyAOP

    {

        public static void Show()

        {

            User user = new User()

            {

                Name = "XF",

                Password = "116"

            };

            UserProcessor processor = new UserProcessor();

            processor.RegUser(user);

            Console.WriteLine("************************");

            UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>();

            userProcessor.RegUser(user);

        }

        public interface IUserProcessor

        {

            void RegUser(User user);

        }

 

        public class XFRealProxy<T> : RealProxy

        {

            private T t;

            public XFRealProxy(T target) : base(typeof(T))

            {

                this.t = target;

            }

            public override IMessage Invoke(IMessage msg)

            {

                BeforeProceede(msg);

                IMethodCallMessage callMessage = (IMethodCallMessage)msg;

                object returnValue = callMessage.MethodBase.Invoke(this.t, 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("方法执行后加入逻辑");

            }

        }

        public static class TransparentProxy

        {

            public static T Create<T>()

            {

                T instance = Activator.CreateInstance<T>();

                XFRealProxy<T> realProxy = new XFRealProxy<T>(instance);

                T transparentProxy = (T)realProxy.GetTransparentProxy();

                return transparentProxy;

            }

        }

        /// <summary>

        /// 继承MarshalByRefObject父类,在支持远程处理的应用程序中,允许跨应用程序域边界访问对象。

        /// </summary>

        public class UserProcessor : MarshalByRefObject, IUserProcessor

        {

            public void RegUser(User user)

            {

                Console.WriteLine($"用户已注册,用户名称{user.Name},密码:{user.Password}");

            }

        }

 

}

1.3.2  Castle实现

/// <summary>

    /// 使用Castle\DynamicProxy实现动态代理

    /// 方法是虚方法

    /// </summary>

    public class CastleProxyAOP

    {

        public static void Show()

        {

            User user = new User()

            {

                Name = "XF",

                Password = "12345"

            };

            ProxyGenerator generator = new ProxyGenerator();

            XFInterceptor interceptor = new XFInterceptor();

            UserProcessor userProcessor = generator.CreateClassProxy<UserProcessor>(interceptor);

            userProcessor.RegUser(user);

        }

        public interface IUserProcessor

        {

            void RegUser(User user);

        }

        public class UserProcessor : IUserProcessor

        {

            public virtual void RegUser(User user)

            {

                Console.WriteLine($"用户注册,Name {user.Name},Password {user.Password}");

            }

        }

 

        public class XFInterceptor: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("方法执行后");

            }

        }

    }

1.4        Unity、MVC中的AOP

1.4.1  Unitiy实现AOP

需要先在NuGet中引用如下组件:

Unity、Unity.Interception、Unity.Configuration

Unity.Interception.Configuration

1.4.1.1      IUserProcessor

定义接口

public interface IUserProcessor

    {

        void RegUser(User user);

        User GetUser(User user);

}

1.4.1.2      UserProcessor

接口的实现类

public class UserProcessor:IUserProcessor

    {

        public void RegUser(User user)

        {

            Console.WriteLine("用户注册");

        }

        public User GetUser(User user)

        {

            return user;

        }

    }

1.4.1.3      MonitorBehavior

AOP添加的性能检测方法

public class MonitorBehavior: Unity.Interception.InterceptionBehaviors.IInterceptionBehavior

    {

        public bool WillExecute

        {

            get { return true; }

        }

 

        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;

        }      

    }

1.4.1.4      LogBeforeBehavior

AOP添加的日志记录方法

public class LogBeforeBehavior : Unity.Interception.InterceptionBehaviors.IInterceptionBehavior

    {

        public bool WillExecute

        {

            get { return true; }

        }

 

        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);

        }

1.4.1.5      ParameterCheckBehavior

AOP添加的参数检查方法

public class ParameterCheckBehavior : Unity.Interception.InterceptionBehaviors.IInterceptionBehavior

    {

        public bool WillExecute { get { return true; } }

 

        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 < 3)

                return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于3位"));

            else

            {

                Console.WriteLine("参数检测无误");

                return getNext().Invoke(input, getNext);

            }

        }

    }

1.4.1.6      CachingBehavior

AOP添加的缓存方法

public class CachingBehavior : Unity.Interception.InterceptionBehaviors.IInterceptionBehavior

    {

        public bool WillExecute

        {

            get { return true; }

        }

 

        public IEnumerable<Type> GetRequiredInterfaces()

        {

            return Type.EmptyTypes;

        }

 

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)

        {

            Console.WriteLine("CachingBehavior");

            if (input.MethodBase.Name.Equals("GetUser"))

                return input.CreateMethodReturn(new User() { Id = 116, Name = "XF" });

            return getNext().Invoke(input, getNext);

        }

    }

1.4.1.7      ExceptionLoggingBehavior

AOP添加的异常记录方法

public class ExceptionLoggingBehavior : Unity.Interception.InterceptionBehaviors.IInterceptionBehavior

    {

        public bool WillExecute

        {

            get { return true; }

        }

 

        public IEnumerable<Type> GetRequiredInterfaces()

        {

            return Type.EmptyTypes;

        }

 

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)

        {

            Console.WriteLine("ExceptionLoggingBehavior");

            IMethodReturn methodReturn = getNext().Invoke(input, getNext);

            if (methodReturn.Exception == null)

                Console.WriteLine("无异常");

            else

                Console.WriteLine($"异常:{methodReturn.Exception.Message}");

            return methodReturn;

        }

    }

1.4.1.8      LogAfterBehavior

AOP添加的日志记录方法

public class LogAfterBehavior : Unity.Interception.InterceptionBehaviors.IInterceptionBehavior

    {

        public bool WillExecute

        {

            get { return true; }

        }

 

        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().Invoke(input, getNext);

            Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);

            return methodReturn;

        }

    }

1.4.1.9      UnityConfigAOP

public class UnityConfigAOP

    {

        public static void Show()

        {

            User user = new User()

            {

                Name = "XF",

                Password = "116"

            };

            #region配置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 configurationSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            configurationSection.Configure(container, "AOPContainer");

            #endregion

            IUserProcessor processor = container.Resolve<IUserProcessor>();

            processor.RegUser(user);

            processor.GetUser(user);

        }

    }