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
付费内容,请联系本人QQ:1002453261
本文来自博客园,作者:明志德道,转载请注明原文链接:https://www.cnblogs.com/for-easy-fast/articles/12430089.html