一丶前言 看過一些描述關於AOP切麵編程的文章,寫的太概念化讓人很難理解,下麵是我自己的理解,希望能幫到新人,如有錯誤歡迎指正。 二丶AOP是什麼,它的應用場景是什麼? AOP也跟IOC,OOP這些思想一樣它只是一種編程思想。Autofac、Spring.Net、Castle這些組件實現了AOP切麵 ...
一丶前言
看過一些描述關於AOP切麵編程的文章,寫的太概念化讓人很難理解,下麵是我自己的理解,希望能幫到新人,如有錯誤歡迎指正。
二丶AOP是什麼,它的應用場景是什麼?
AOP也跟IOC,OOP這些思想一樣它只是一種編程思想。Autofac、Spring.Net、Castle這些組件實現了AOP切麵編程思想的框架。AOP說白了就是在運行時,動態的將代碼切入到類的指定方法的指定位置上,這種思想就是面向切麵的編程思想。
如果你發現你的方法中有很多重覆的代碼就可以考慮用aop來精簡代碼了。比如說你想監控每個方法的耗時,按照傳統的方法是每個方法都加上監控代碼,如果用AOP思想去解決這個問題,就可以把監控代碼放到方法的外面去寫。
AOP思想的應用場景:
AOP切麵緩存
許可權認證
錯誤處理
調試
日誌記錄
性能監控
數據持久化
AOP事務
三丶AOP切麵執行流程
AOP切麵有點像攔截器,不過跟攔截器有點區別。
四丶代碼例子
這個例子開發環境使用的是.Net Core 3.0,用的AOP框架是Autofac,通過Nuget安裝Autofac.Extras.DynamicProxy組件。
功能是AOP切麵緩存,把查詢結果緩存到Redis里,不用每次都查詢資料庫。
使用步驟
1.Startup中把BlogCacheAOP切麵 切入到Titan.Blog.AppService.dll下所有介面實現里。
var servicesDllFile = Path.Combine(basePath, "Titan.Blog.AppService.dll");//獲取項目絕對路徑 var assemblysServices = Assembly.LoadFile(servicesDllFile); builder.RegisterAssemblyTypes(assemblysServices) .AsImplementedInterfaces() .InstancePerLifetimeScope() .EnableInterfaceInterceptors() .InterceptedBy(typeof(BlogCacheAOP));//AOP切麵緩存
2.切麵公共代碼
3.給方法標記特性,只有指定特性的方法才會執行公共代碼
/// <summary> /// 獲取系統中所有的許可權 /// </summary> /// <returns></returns> [Caching(AbsoluteExpiration = 10)] public async Task<List<SysRoleModuleButtonDto>> GeRoleModule() { var dto = await _iSysRoleModuleButtonRepository.QueryAsNoTracking(x => x.ModuleType == 0);// var roleModuleButton = dto.MapToList<SysRoleModuleButton, SysRoleModuleButtonDto>(); if (roleModuleButton.Count > 0) { foreach (var item in roleModuleButton) { item.SysRole = _iSysRoleRepository.QueryBySql($"select * from SysRole where SysRoleId='{item.SysRoleId}' and IsDelete!=1 and RoleStatus=1").Result.FirstOrDefault(); item.SysModule = _iSysModuleRepository.QueryBySql($"select * from SysModule where SysModuleId='{item.SysModuleId}' and ModuleStatus=1 and IsDelete!=1").Result.FirstOrDefault(); } } return roleModuleButton; }
這個是AOP切麵緩存,它的功能是將包含CachingAttribute特性的方法的返回值緩存到Redis里,下次在訪問這個方法,會先去緩存中查詢如果有則直接跳過這個方法,直接從Redis里獲取之前緩存的結果集,如果沒有則會執行方法獲取返回值在緩存到Redis里。
以此,我們可以開發其他類似功能,比如性能監控,日誌監控,AOP事務,是不是很強大。具體代碼執行流程請下載這個項目(下麵有github地址),自己調試下上面的例子就明白了。
*****還有一個要註意的,我這個項目控制器和服務實現解耦了,如果沒有解耦的話,控制器直接調服務的話,AOP註冊方式和服務要做修改。
1.Startup中AOP註冊代碼
////標記了虛方法virtual的才會進入切麵 var assemblysModels = Assembly.Load("Titan.Blog.AppService"); builder.RegisterAssemblyTypes(assemblysModels) .EnableClassInterceptors() .InterceptedBy(typeof(BlogCacheAOP));
2.方法要加上virtual,否則進不了切麵
/// <summary> /// 獲取系統中所有的許可權 /// </summary> /// <returns></returns> [Caching(AbsoluteExpiration = 10)] public virtual async Task<List<SysRoleModuleButtonDto>> GeRoleModule() { var dto = await _iSysRoleModuleButtonRepository.QueryAsNoTracking(x => x.ModuleType == 0);// var roleModuleButton = dto.MapToList<SysRoleModuleButton, SysRoleModuleButtonDto>(); if (roleModuleButton.Count > 0) { foreach (var item in roleModuleButton) { item.SysRole = _iSysRoleRepository.QueryBySql($"select * from SysRole where SysRoleId='{item.SysRoleId}' and IsDelete!=1 and RoleStatus=1").Result.FirstOrDefault(); item.SysModule = _iSysModuleRepository.QueryBySql($"select * from SysModule where SysModuleId='{item.SysModuleId}' and ModuleStatus=1 and IsDelete!=1").Result.FirstOrDefault(); } } return roleModuleButton; }
3.切麵代碼不需要改動
四丶結語
AOP思想實際上就是想把業務和公共的處理分開,對原有的代碼沒有一點入侵。我覺得學習一個新技術之前,先別讀那麼多概念性的東西,感覺越看越糊塗,只會對學習新技術產生恐懼和抵觸心理。我們可以先看看新技術它能解決什麼問題,實際應用場景是什麼,這對學習新技術應該是有好處的。
五丶Github Demo,演示地址
演示地址:http://gaobili.cn:8600/swagger/index.html
加群一起學習共同進步。群號:963718093