【代码设计】C# 实现 AOP 面向切面编程

打印 上一主题 下一主题

主题 1829|帖子 1829|积分 5487

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
    简单记录一下对AOP的认识,正文为3个部分
    一、AOP由来
    二、用DispatchProxy动态代理实现AOP
    三、通过特性标记,处理多种不同执行前、执行后的逻辑编排
 
一、AOP 由来
  1.     IUserHelper userHelper = new CommonUserHelper();<br>    // commonUser.Create中存在 方法执行前、方法执行后的业务逻辑
  2.     userHelper.Create("test0401_A");
  3.     public interface IUserHelper
  4.     {
  5.         void Create(string name);
  6.     }
  7.     public class CommonUserHelper : IUserHelper
  8.     {
  9.         private void before()
  10.         {
  11.             Console.WriteLine("CommonUser before");
  12.         }
  13.         private void after()
  14.         {
  15.             Console.WriteLine("CommonUser after");
  16.         }
  17.         public void Create(string name)
  18.         {
  19.             before();
  20.             Console.WriteLine($"  Common User : {name} Created !");
  21.             after();
  22.         }
  23.     }
  24. <br>
复制代码
CommonUserHelper 实现 IUserHelper 接口,假设希望在 Create方法执行前/后写入日志,那就存在这4种业务逻辑:
  ① 执行前写入日志,执行 Create
  ② 执行前写入日志,执行 Create,执行后写入日志
  ③ 执行 Create,执行后写入日志
  ④ 执行 Create
  单一个写日志的需求,就能有4种实现方式,极端情况下,是可以实现 4次 Create 方法;
  如果再加一个数据验证、IP验证、权限验证、异常处理、加入缓存..,那么实现的排列组合方式就更多了,
  无穷尽地加实现、替换类,这显然不是我们希望的。
AOP,Aspect Oriented Programing,是一种编程思维,是对这种缺陷的补充。
 
二、DispatchProxy (动态代理)实现AOP
  1. using System.Reflection;
  2. namespace Cjm.AOP
  3. {
  4.     public class TransformProxy
  5.     {
  6.         public static T GetDynamicProxy<T>(T instance)  
  7.         {
  8.             // DispatchProxy 是system.Reflection封装的类
  9.             // 用以创建实现接口T的代理类CustomProxy的实例
  10.             dynamic obj = DispatchProxy.Create<T, CustomProxy<T>>();
  11.             obj.Instance = instance;
  12.             return (T)obj;
  13.         }
  14.     }
  15.     // DispatchProxy 是抽象类,
  16.     // 实现该类的实例,实例方法执行是会跳转到 Invoke 方法中,
  17.     // 以此达到不破坏实际执行的具体逻辑,而又可以在另外的地方实现执行前、执行后
  18.     public class CustomProxy<T> : DispatchProxy
  19.     {
  20.         public T Instance { get; set; }
  21.         protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
  22.         {
  23.             BeforeProcess();
  24.             var relt = targetMethod?.Invoke(Instance, args);
  25.             AfterProcess();
  26.             return relt;
  27.         }
  28.         private void BeforeProcess()
  29.         {
  30.             Console.WriteLine($"This is BegoreProcess.");
  31.         }
  32.         private void AfterProcess()
  33.         {
  34.             Console.WriteLine($"This is AfterProcess.");
  35.         }
  36.     }
  37. }
  38.     // Main
  39.     IUserHelper userHelper3 = new CommonUserHelper();
  40.     userHelper3 = TransformProxy.GetDynamicProxy(userHelper3);
  41.     userHelper3.Create("test0401_B");
复制代码
 
三、通过标记特性,处理多种不同的执行前/执行后方法

  此处借用Castle.Core的封装(可通过Nuget管理下载),
  通过实现 StandardInterceptor以重写 执行前/执行后 逻辑的封装方式,
  我们可以更加聚焦在如何处理多种 执行前/执行后 逻辑的编排上。
  1. using Castle.DynamicProxy;
  2. {
  3.     ProxyGenerator proxy = new ProxyGenerator();
  4.     CustomInterceptor customInterceptor = new CustomInterceptor();
  5.     IUserHelper commonUserHelper = new CommonUserHelper();
  6.     var userHelperProxy = proxy.CreateInterfaceProxyWithTarget<IUserHelper>(commonUserHelper, customInterceptor);
  7.     userHelperProxy.Create("TEST0401_C");
  8. }   
复制代码
  1.     public class CustomInterceptor : StandardInterceptor
  2.     {
  3.         protected override void PreProceed(IInvocation invocation)
  4.         {
  5.             var method = invocation.Method;
  6.             //if (method.IsDefined(typeof(LogBeforeAttribute), true))
  7.             //{
  8.             //    Console.WriteLine("LOG : CustomInterceptor.PreProceed");
  9.             //}
  10.             Action<IInvocation> action = (invocation) => base.PreProceed(invocation);
  11.             // 获取该方法的所有继承BaseAOPAttribute的特性
  12.             var attrs = method.GetCustomAttributes<BaseAOPAttribute>(true);<br>            // 对于 attrs 的排列顺序,可以在特性的实现中增加 int order 属性,在标记特性时写入排序编号
  13.             foreach(var attr in attrs)
  14.             {
  15.                 // 这里是俄罗斯套娃
  16.                 // 相当于 attr3.AOPAction(invocation, attr2.AOPAction(invocation, attr1.AOPAction(invocation, base.PreProceed(invocation))))
  17.                 action = attr.AOPAction(invocation, action);
  18.             }
  19.             action.Invoke(invocation);
  20.         }
  21.         protected override void PerformProceed(IInvocation invocation)
  22.         {
  23.             Console.WriteLine("CustomInterceptor.PerformProceed");
  24.             base.PerformProceed(invocation);
  25.         }
  26.         protected override void PostProceed(IInvocation invocation)
  27.         {
  28.             var method = invocation.Method;
  29.             if (method.IsDefined(typeof(LogAfterAttribute), true))
  30.             {
  31.                 Console.WriteLine("LOG : CustomInterceptor.PostProceed");
  32.             }
  33.             base.PreProceed(invocation);
  34.         }
  35.     }
复制代码
  1.     public class LogBeforeAttribute : Attribute {}
  2.     public class LogAfterAttribute : Attribute {}
  3.     public class CheckIPAttribute : BaseAOPAttribute
  4.     {
  5.         public override Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action)
  6.         {
  7.             return (invocation) => {
  8.                 Console.WriteLine("CheckIP ..");
  9.                 action.Invoke(invocation); <br>            };
  10.         }
  11.     }
  12.     public abstract class BaseAOPAttribute : Attribute
  13.     {
  14.         public abstract Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action);
  15.     }
复制代码
  通过给方法标记特性的方式,达到切面编程的目的(不影响原有实现,而增加实现执行前/执行后的逻辑)
  1.     public interface IUserHelper
  2.     {
  3.         [LogBefore]
  4.         [LogAfter]
  5.         [CheckIP]
  6.         void Create(string name);
  7.         void CreateNoAttri();
  8.     }
复制代码
 
============================================================
具体的AOP实现上需要考虑的问题多如牛毛,此处仅做简单的思路介绍。
以上主要参考自 B站 朝夕教育 2022 .Net Core AOP实现。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

北冰洋以北

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表