一.AOP概述:
AOP(Aspect Oriented Programming),即面向切面編程。采用“橫切”的思想,將軟件系統的系統功能和業務功能分開。
系統功能主要有:
1.緩存模塊:用於緩存數據,與系統業務功能關系不大,用於提升系統性能。當數據請求過來時,是否要從緩存讀取,當緩存沒有數據時,
是否要將獲取到的數據放入緩存,以便下次數據請求時從緩存讀取。比較常用的緩存工具有monogodb,redis。
2.驗證模塊:判斷當前用戶是否有獲取該條數據 或者執行 該操作的權限。
3.日志模塊:收集當前用戶的操作痕跡,或者記錄系統出現的問題,后期可進行大數據行為分析。
業務功能:系統處理用戶請求的正常邏輯功能。
http請求過來后,會先經過系統功能的橫切攔截,才會到業務功能處理請求。AOP具體過程如下圖所示:
二、AOP實現:
國內大佬基於.NETStand 實現了一個AOP的框架,其源碼地址為 https://github.com/dotnetcore/AspectCore-Framework。
要使用該框架,可通過Nuget 將 AspectCore.Extensions.DependencyInjection 引用到項目中,可實現日志攔截和緩存攔截,該框架是基於IOC容器的。
這里,我用控制台程序來演示:首先,先nuget 引用 AspectCore.Extensions.DependencyInjection。
1.程序入口:
class Program { static void Main(string[] args) { //創建用於注冊服務的IOC容器 ServiceCollection ServiceCollection services = new ServiceCollection(); //在容器中 注冊服務 services.ConfigureDynamicProxy(); services.AddScoped<IMySql, MySql>(); //創建ServiceProvider,用於獲取服務。 var provider = services.BuildDynamicProxyProvider(); //獲取服務。 var mysql = provider.GetService<IMySql>(); //執行服務。 var msg=mysql.GetById(10); //第一次去數據,從業務邏輯取數據 var value = mysql.GetData("hehe"); Console.WriteLine(value); //第二次去數據,從緩存取 value = mysql.GetData("hehe"); Console.WriteLine(value); Console.ReadKey(); Console.WriteLine("Hello World!"); } }
2.系統功能 切面部分(AOP):
日志切面:
/// <summary> /// 日志模塊:(日志切面,日志AOP) /// </summary> public class MyLogInterceptorAttribute : AbstractInterceptorAttribute { /// <summary> /// /// </summary> /// <param name="context">委托的參數,這里傳遞的是 GetById 方法</param> /// <param name="next">委托,委托的動作要看具體傳進來的方法的動作是什么</param> /// <returns></returns> public override Task Invoke(AspectContext context, AspectDelegate next) { Console.WriteLine("開始記錄日志......."); //var aa = context; //var bb = next; var task = next(context);//從這里開始執行具體的方法。這里執行的是 GetById; Console.WriteLine("結束記錄日志......."); return task; } }
緩存切面:
public class MyCacheInterceptorAttribute : AbstractInterceptorAttribute { //用於模擬緩存 private Dictionary<string, string> CacheDic = new Dictionary<string, string>(); /// <summary> /// /// </summary> /// <param name="context">委托的參數,這里傳遞的是 GetById 方法</param> /// <param name="next">委托,委托的動作,要看具體傳進來的方法的動作是什么</param> /// <returns></returns> public override Task Invoke(AspectContext context, AspectDelegate next) { //獲取 傳遞過來的AspectContext,即傳進來的方法 的參數。 var cacheKey = string.Join(",", context.Parameters); //從緩存去數據。如果緩存有,則返回 if (CacheDic.ContainsKey(cacheKey)) { context.ReturnValue = CacheDic[cacheKey].ToString(); return Task.CompletedTask; } //緩存沒有,從業務邏輯取數據,去到數據后,將數據放入緩存 var task = next(context); var cacheValue = context.ReturnValue.ToString(); CacheDic.Add(cacheKey, "From cache:"+cacheValue); return task; } }
3.業務功能部分:
public interface IMySql { string GetById(int id); string GetData(string key); } public class MySql : IMySql { [MyLogInterceptor] //日志切面 public string GetById(int id) { var msg = $"已經獲取到ID為{id}的數據"; Console.WriteLine(id); return msg; } [MyCacheInterceptor] //緩存切面 public string GetData(string key) { return "獲取數據"; } }