本章將簡單介紹下AOP面向切面編程,首先我們先來看些概念,
POP面向程序編程:符合邏輯思維,線性的處理問題-----無法應付復雜的系統,
OOP面向物件編程:
萬物皆物件,物件互動完成功能,功能疊加成模塊,模塊組成系統,去搭建復雜的大型軟體系統,
類卻是會變化的,增加日志/例外/權限/快取/事務,只能修改類?
只能替換整個物件,沒辦法把一個類動態改變,
GOF的23種設計模式,應對變化,核心套路是依賴抽象,細節就可以變化,
AOP面向切面編程:
是一種編程思想,是OOP思想的補充,
允許開發者動態的修改靜態的OO模型,就像現實生活中物件在生命周期中會不斷的改變自身,
正是因為能夠動態的擴展功能,所以在程式設計時就可以有以下好處:
1、只需要聚焦核心業務邏輯,權限/例外/日志/快取/事務等通用功能可以通過AOP方式添加,使程式設計變得更加簡單,
2、功能動態擴展;集中管理;代碼復用;規范化;
實作AOP的多種方式:
1、靜態實作---裝飾器模式/代理模式,
2、動態實作---Remoting/Castle(Emit)
3、靜態織入---PostSharp(收費)---擴展編譯工具,生成的加入額外代碼,
4、依賴注入容器的AOP擴展(開發)
5、MVC的Filter---特性標記,然后該方法執行前/后就多了邏輯,
下面看一張圖來輔助我們了解:

從圖中一刀切過去將核心業務邏輯和我們的通用功能分離,這樣的話我們只需要聚焦核心業務邏輯,而權限/例外/日志/快取/事務等通用功能可以通過AOP方式添加,使程式設計變得更加簡單,
下面我們重點來看下代碼如何實作,為了演示此處我們使用VS2017建個控制臺專案MyAOP,目標框架為:.NET Framework 4.6.1,如下所示:

一、代理模式實作靜態代理(靜態實作AOP)
using System; namespace MyAOP { /// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } }
using System; namespace MyAOP { /// <summary> /// 代理模式實作靜態代理 /// AOP 在方法前后增加自定義的方法 /// </summary> public class ProxyAOP { public static void Show() { User user = new User() { Name = "浪子天涯", Password = "123456" }; IUserProcessor processor = new UserProcessor(); processor.RegUser(user); Console.WriteLine("***************"); processor = new ProxyUserProcessor(); processor.RegUser(user); } public interface IUserProcessor { void RegUser(User user); } public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用戶已注冊,Name:{0},PassWord:{1}", user.Name, user.Password); } } /// <summary> /// 代理模式去提供一個AOP功能 /// </summary> public class ProxyUserProcessor : IUserProcessor { private IUserProcessor _userProcessor = new UserProcessor(); public void RegUser(User user) { BeforeProceed(user); this._userProcessor.RegUser(user); AfterProceed(user); } /// <summary> /// 業務邏輯之前 /// </summary> private void BeforeProceed(User user) { Console.WriteLine("方法執行前"); } /// <summary> /// 業務邏輯之后 /// </summary> private void AfterProceed(User user) { Console.WriteLine("方法執行后"); } } } }
看下呼叫ProxyAOP.Show()的結果:

二、裝飾器模式實作靜態代理(靜態實作AOP)
using System; namespace MyAOP { /// <summary> /// 裝飾器模式實作靜態代理 /// AOP 在方法前后增加自定義的方法 /// </summary> public class DecoratorAOP { public static void Show() { User user = new User() { Name = "浪子天涯", Password = "88888888" }; IUserProcessor processor = new UserProcessor(); processor.RegUser(user); Console.WriteLine("***************"); processor = new UserProcessorDecorator(processor); processor.RegUser(user); } public interface IUserProcessor { void RegUser(User user); } public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用戶已注冊,Name:{0},PassWord:{1}", user.Name, user.Password); } } /// <summary> /// 裝飾器模式去提供一個AOP功能 /// </summary> public class UserProcessorDecorator : IUserProcessor { private IUserProcessor _userProcessor { get; set; } public UserProcessorDecorator(IUserProcessor userprocessor) { this._userProcessor = userprocessor; } public void RegUser(User user) { BeforeProceed(user); this._userProcessor.RegUser(user); AfterProceed(user); } /// <summary> /// 業務邏輯之前 /// </summary> private void BeforeProceed(User user) { Console.WriteLine("方法執行前"); } /// <summary> /// 業務邏輯之后 /// </summary> private void AfterProceed(User user) { Console.WriteLine("方法執行后"); } } } }
看下呼叫DecoratorAOP.Show()的結果:

3、使用Unity容器實作AOP
首先來看下專案的目錄結構:

需要從NuGet上安裝如下程式包:

核心業務邏輯:
using System; namespace MyAOP.UnityWay { public interface IUserProcessor { //[Obsolete] //此處可擴展 void RegUser(User user); User GetUser(User user); } }
using System; namespace MyAOP.UnityWay { public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用戶已注冊,"); } public User GetUser(User user) { return user; } } }
AOP擴展:
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { /// <summary> /// 快取AOP擴展 /// </summary> public class CachingBehavior : IInterceptionBehavior { /// <summary> /// 固定寫法 /// </summary> public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("CachingBehavior"); //input.Target.GetType().GetCustomAttributes() if (input.MethodBase.Name.Equals("GetUser")) return input.CreateMethodReturn(new User() { Id = 234, Name = "Eleven" }); return getNext().Invoke(input, getNext); } /// <summary> /// 固定寫法 /// </summary> public bool WillExecute { get { return true; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { public class ExceptionLoggingBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("ExceptionLoggingBehavior"); IMethodReturn methodReturn = getNext()(input, getNext); if (methodReturn.Exception == null) { Console.WriteLine("無例外"); } else { Console.WriteLine($"例外:{methodReturn.Exception.Message}"); } return methodReturn; } public bool WillExecute { get { return true; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { public class LogAfterBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("LogAfterBehavior"); foreach (var item in input.Inputs) { Console.WriteLine(item.ToString());//反射獲取更多資訊 } IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue); return methodReturn; } public bool WillExecute { get { return true; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { /// <summary> /// 不需要特性 /// </summary> public class LogBeforeBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("LogBeforeBehavior"); foreach (var item in input.Inputs) { Console.WriteLine(item.ToString());//反射獲取更多資訊 } return getNext().Invoke(input, getNext); } public bool WillExecute { get { return true; } } } }
using System; using System.Collections.Generic; using System.Diagnostics; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { /// <summary> /// 性能監控的AOP擴展 /// </summary> public class MonitorBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine(this.GetType().Name); string methodName = input.MethodBase.Name; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); var methodReturn = getNext().Invoke(input, getNext);//后續邏輯執行 stopwatch.Stop(); Console.WriteLine($"{this.GetType().Name}統計方法{methodName}執行耗時{stopwatch.ElapsedMilliseconds}ms"); return methodReturn; } public bool WillExecute { get { return true; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { public class ParameterCheckBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("ParameterCheckBehavior"); User user = input.Inputs[0] as User; if (user.Password.Length < 10) { return input.CreateExceptionMethodReturn(new Exception("密碼長度不能小于10位")); } else { Console.WriteLine("引數檢測無誤"); return getNext().Invoke(input, getNext); } } public bool WillExecute { get { return true; } } } }
Unity.config組態檔:
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
<!--Microsoft.Practices.Unity.Configuration.UnityConfigurationSection-->
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="aopContainer">
<extension type="Interception"/>
<register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP">
<interceptor type="InterfaceInterceptor"/>
<interceptionBehavior type="MyAOP.UnityWay.MonitorBehavior, MyAOP"/>
<interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/>
<interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/>
<interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/>
<interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/>
<interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/>
</register>
</container>
</containers>
</unity>
</configuration>
注意:編譯時需要將組態檔輸出到bin/debug目錄下,設定如下所示:

使用如下:
using System; using System.IO; using System.Configuration; using Microsoft.Practices.Unity.Configuration; using Unity; namespace MyAOP.UnityWay { public class UnityConfigAOP { public static void Show() { User user = new User() { Name = "浪子天涯", Password = "12345678910" }; //配置UnityContainer IUnityContainer container = new UnityContainer(); ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); configSection.Configure(container, "aopContainer"); IUserProcessor processor = container.Resolve<IUserProcessor>(); processor.RegUser(user); processor.GetUser(user); } } }
呼叫UnityConfigAOP.Show()的結果如下:

可以發現執行順序就像俄羅斯套娃,如下所示:

Demo原始碼:
鏈接:https://pan.baidu.com/s/147Veb1fU49sT5bcEbgrERw 提取碼:j5ml
此文由博主精心撰寫轉載請保留此原文鏈接:https://www.cnblogs.com/xyh9039/p/13532063.html
著作權宣告:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/1601.html
標籤:ASP.NET
上一篇:分享專案中在用的asp.net下載業務的服務端基類(支持客戶端顯示下載百分比進度,支持并發數控制,支持限速)
下一篇:.NET異步和多執行緒系列(一)
