簡單記錄一下對AOP的認識,正文為3個部分 一、AOP由來 二、用DispatchProxy動態代理實現AOP 三、通過特性標記,處理多種不同執行前、執行後的邏輯編排 一、AOP 由來 IUserHelper userHelper = new CommonUserHelper(); // commo ...
簡單記錄一下對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實現。