【代码设计】C# 实现 AOP 面向切面编程
简单记录一下对AOP的认识,正文为3个部分
一、AOP 由来
IUserHelper userHelper = new CommonUserHelper();
// commonUser.Create中存在 方法执行前、方法执行后的业务逻辑 userHelper.Create("test0401_A"); public interface IUserHelper { void Create(string name); } public class CommonUserHelper : IUserHelper { private void before() { Console.WriteLine("CommonUser before"); } private void after() { Console.WriteLine("CommonUser after"); } public void Create(string name) { before(); Console.WriteLine($" Common User : {name} Created !"); after(); } }
CommonUserHelper 实现 IUserHelper 接口,假设希望在 Create方法执行前/后写入日志,那就存在这4种业务逻辑:
① 执行前写入日志,执行 Create
② 执行前写入日志,执行 Create,执行后写入日志
③ 执行 Create,执行后写入日志
④ 执行 Create
单一个写日志的需求,就能有4种实现方式,极端情况下,是可以实现 4次 Create 方法;
如果再加一个数据验证、IP验证、权限验证、异常处理、加入缓存..,那么实现的排列组合方式就更多了,
无穷尽地加实现、替换类,这显然不是我们希望的。
AOP,Aspect Oriented Programing,是一种编程思维,是对这种缺陷的补充。
二、DispatchProxy (动态代理)实现AOP
using System.Reflection; namespace Cjm.AOP { public class TransformProxy { public static T GetDynamicProxy<T>(T instance) { // DispatchProxy 是system.Reflection封装的类 // 用以创建实现接口T的代理类CustomProxy的实例 dynamic obj = DispatchProxy.Create<T, CustomProxy<T>>(); obj.Instance = instance; return (T)obj; } } // DispatchProxy 是抽象类, // 实现该类的实例,实例方法执行是会跳转到 Invoke 方法中, // 以此达到不破坏实际执行的具体逻辑,而又可以在另外的地方实现执行前、执行后 public class CustomProxy<T> : DispatchProxy { public T Instance { get; set; } protected override object? Invoke(MethodInfo? targetMethod, object?[]? args) { BeforeProcess(); var relt = targetMethod?.Invoke(Instance, args); AfterProcess(); return relt; } private void BeforeProcess() { Console.WriteLine($"This is BegoreProcess."); } private void AfterProcess() { Console.WriteLine($"This is AfterProcess."); } } } // Main IUserHelper userHelper3 = new CommonUserHelper(); userHelper3 = TransformProxy.GetDynamicProxy(userHelper3); userHelper3.Create("test0401_B");
三、通过标记特性,处理多种不同的执行前/执行后方法
此处借用Castle.Core的封装(可通过Nuget管理下载),
通过实现 StandardInterceptor以重写 执行前/执行后 逻辑的封装方式,
我们可以更加聚焦在如何处理多种 执行前/执行后 逻辑的编排上。
using Castle.DynamicProxy; { ProxyGenerator proxy = new ProxyGenerator(); CustomInterceptor customInterceptor = new CustomInterceptor(); IUserHelper commonUserHelper = new CommonUserHelper(); var userHelperProxy = proxy.CreateInterfaceProxyWithTarget<IUserHelper>(commonUserHelper, customInterceptor); userHelperProxy.Create("TEST0401_C"); }
public class CustomInterceptor : StandardInterceptor { protected override void PreProceed(IInvocation invocation) { var method = invocation.Method; //if (method.IsDefined(typeof(LogBeforeAttribute), true)) //{ // Console.WriteLine("LOG : CustomInterceptor.PreProceed"); //} Action<IInvocation> action = (invocation) => base.PreProceed(invocation); // 获取该方法的所有继承BaseAOPAttribute的特性 var attrs = method.GetCustomAttributes<BaseAOPAttribute>(true);
// 对于 attrs 的排列顺序,可以在特性的实现中增加 int order 属性,在标记特性时写入排序编号 foreach(var attr in attrs) { // 这里是俄罗斯套娃 // 相当于 attr3.AOPAction(invocation, attr2.AOPAction(invocation, attr1.AOPAction(invocation, base.PreProceed(invocation)))) action = attr.AOPAction(invocation, action); } action.Invoke(invocation); } protected override void PerformProceed(IInvocation invocation) { Console.WriteLine("CustomInterceptor.PerformProceed"); base.PerformProceed(invocation); } protected override void PostProceed(IInvocation invocation) { var method = invocation.Method; if (method.IsDefined(typeof(LogAfterAttribute), true)) { Console.WriteLine("LOG : CustomInterceptor.PostProceed"); } base.PreProceed(invocation); } }
public class LogBeforeAttribute : Attribute {} public class LogAfterAttribute : Attribute {} public class CheckIPAttribute : BaseAOPAttribute { public override Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action) { return (invocation) => { Console.WriteLine("CheckIP .."); action.Invoke(invocation);
}; } } public abstract class BaseAOPAttribute : Attribute { public abstract Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action); }
通过给方法标记特性的方式,达到切面编程的目的(不影响原有实现,而增加实现执行前/执行后的逻辑)
public interface IUserHelper { [LogBefore] [LogAfter] [CheckIP] void Create(string name); void CreateNoAttri(); }
============================================================
具体的AOP实现上需要考虑的问题多如牛毛,此处仅做简单的思路介绍。
以上主要参考自 B站 朝夕教育 2022 .Net Core AOP实现。