官方解釋:AOP(Aspect-Oriented Programming,面向切面編程),它是能夠經過預編譯方式和運行期動態代理實如今不修改源代碼的狀況下給程序動態統一添加功能的一種技術。它是一種新的方法論,是對傳統OOP編程的一種補充。OOP是關注將需求功能劃分爲不一樣的而且相對獨立、封裝良好的類,並讓它們有着屬於本身的行爲,依靠繼承和多態等來定義彼此的關係;AOP是但願可以將通用需求功能從不相關的類當中分離出來,可以使得不少類共享一個行爲,一旦發生變化,沒必要修改不少類,而只須要修改這個行爲便可。AOP是使用切面(aspect)將橫切關注點模塊化,OOP是使用類將狀態和行爲模塊化。在OOP的世界中,程序都是經過類和接口組織的,使用它們實現程序的核心業務邏輯是十分合適,可是對於實現橫切關注點(跨越應用程序多個模塊的功能需求)則十分吃力,好比日誌記錄、權限驗證、異常攔截等。html
我的理解:AOP就是將公用功能提取出來,若是之後公用功能的需求發生變化,只須要改動公用模塊的代碼便可,多個調用的地方則不須要改動。所謂面向切面,就是隻關注通用功能,而不關注業務邏輯。它實現的方式通常是經過攔截,好比,項目中通常都有權限驗證的功能,進入每一個頁面前都會驗證當前登陸用戶是否有權限查看該界面。咱們不可能說在每一個頁面的初始化方法裏面都去寫這段驗證的代碼,這個時候咱們的AOP就派上用場了。AOP的機制是預先定義一組特性,使它具備攔截方法的功能,可讓你在執行方法以前和以後作你想作的業務,而咱們使用的時候只須要在對應的方法或者類定義上面加上某一個特性就行了。編程
1)將通用功能從業務邏輯中抽離出來,能夠省略大量的重複代碼,有利於代碼的操做和維護。緩存
2)在軟件設計時,抽出通用功能(切面),有利於軟件設計的模塊化,下降軟件架構的複雜度。也就是說通用的功能都是一個個單獨的模塊,在項目的主業務裏面是看不到這些通用功能的設計代碼的。架構
3.1.一、使用裝飾器模式實現靜態代理app
1)新建一個類:DecoratorAOP.cs框架
/// <summary> /// 使用裝飾器模式實現靜態代理 /// </summary> public class DecoratorAOP { /// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } /// <summary> /// 用戶註冊接口 /// </summary> public interface IUserProcessor { void RegUser(User user); } /// <summary> /// 用戶註冊接口實現類 /// </summary> public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}"); } } /// <summary> /// 裝飾器模式實現AOP功能 /// </summary> public class UserProcessorDecorator : IUserProcessor { private IUserProcessor UserProcessor { get; set; } public UserProcessorDecorator(IUserProcessor userProcessor) { UserProcessor = userProcessor; } public void RegUser(User user) { PreProceed(user); UserProcessor.RegUser(user); PostProceed(user); } public void PreProceed(User user) { Console.WriteLine("方法執行前"); } public void PostProceed(User user) { Console.WriteLine("方法執行後"); } } /// <summary> /// 運行測試 /// </summary> public static void Show() { User user = new User() { Name = "Hello", Password = "World" }; IUserProcessor processor = new UserProcessorDecorator(new UserProcessor()); processor.RegUser(user); } }
2)調用:ide
static void Main(string[] args) { #region 使用裝飾器模式實現靜態代理 DecoratorAOP.Show(); Console.Read(); #endregion }
3)運行結果以下:模塊化
上面代碼是模擬用戶註冊的例子:註冊信息提交前,須要作一些準備工做,好比數據有效性校驗等;註冊信息提交後,還須要作日誌記錄等。從上面的代碼能夠看出,咱們經過靜態植入的方式,手動地在執行方法前和執行方法後讓它作一些咱們須要的功能。測試
3.1.二、使用代理模式實現靜態代理ui
1)新建一個類:ProxyAOP.cs
/// <summary> /// 使用代理模式實現靜態代理 /// </summary> public class ProxyAOP { /// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } /// <summary> /// 用戶註冊接口 /// </summary> public interface IUserProcessor { void RegUser(User user); } /// <summary> /// 用戶註冊接口實現類 /// </summary> public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}"); } } /// <summary> /// 代理模式實現AOP功能 /// </summary> public class UserProcessorProxy : IUserProcessor { private IUserProcessor userProcessor = new UserProcessor(); public void RegUser(User user) { PreProceed(user); userProcessor.RegUser(user); PostProceed(user); } private void PreProceed(User user) { Console.WriteLine("方法執行前"); } private void PostProceed(User user) { Console.WriteLine("方法執行後"); } } public static void Show() { User user = new User() { Name = "Hello", Password = "World" }; IUserProcessor processor = new UserProcessorProxy(); processor.RegUser(user); } }
2)調用:
static void Main(string[] args) { #region 使用代理模式實現靜態代理 ProxyAOP.Show(); Console.Read(); #endregion }
3)運行結果以下:
3.2.一、使用.Net Remoting/RealProxy實現動態代理
1)新建一個類:RealProxyAOP.cs
/// <summary> /// 使用.Net Remoting/RealProxy實現動態代理 /// Client - TransparentProxy - RealProxy - Target Object /// 侷限在業務類必須是繼承自MarshalByRefObject類型 /// </summary> public class RealProxyAOP { /// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } /// <summary> /// 用戶註冊接口 /// </summary> public interface IUserProcessor { void RegUser(User user); } /// <summary> /// 用戶註冊接口實現類 /// 必須繼承自MarshalByRefObject父類,不然沒法生成。 /// </summary> public class UserProcessor : MarshalByRefObject, IUserProcessor { public void RegUser(User user) { Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}"); } } /// <summary> /// 真實代理:提供代理的基本功能 /// </summary> public class MyRealProxy<T> : RealProxy { private T _target; public MyRealProxy(T target) : base(typeof(T)) { _target = target; } public override IMessage Invoke(IMessage msg) { PreProceed(msg); IMethodCallMessage callMessage = (IMethodCallMessage)msg; object returnValue = callMessage.MethodBase.Invoke(_target, callMessage.Args); PostProceed(msg); return new ReturnMessage(returnValue, new object[0], 0, null, callMessage); } public void PreProceed(IMessage msg) { Console.WriteLine("方法執行前"); } public void PostProceed(IMessage msg) { Console.WriteLine("方法執行後"); } } /// <summary> /// 透明代理:提供實際對象駐留在客戶端空間中的假象 /// </summary> public static class TransparentProxy { public static T Create<T>() { T instance = Activator.CreateInstance<T>(); MyRealProxy<T> realProxy = new MyRealProxy<T>(instance); T transparentProxy = (T)realProxy.GetTransparentProxy(); return transparentProxy; } } /// <summary> /// 運行測試 /// </summary> public static void Show() { User user = new User() { Name = "Hello", Password = "World" }; UserProcessor processor = TransparentProxy.Create<UserProcessor>(); processor.RegUser(user); } }
2)調用:
static void Main(string[] args) { #region 使用.Net Remoting/RealProxy實現動態代理 RealProxyAOP.Show(); Console.Read(); #endregion }
3)運行結果以下:
3.2.二、使用Castle\DynamicProxy實現動態代理
1)在NuGet中安裝Castle.Core。
2)新建一個類:CastleProxyAOP.cs
/// <summary> /// 使用Castle\DynamicProxy實現動態代理 /// 方法必須是虛方法 /// </summary> public class CastleProxyAOP { /// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } /// <summary> /// 用戶註冊接口 /// </summary> public interface IUserProcessor { void RegUser(User user); } /// <summary> /// 用戶註冊接口實現類 /// </summary> public class UserProcessor : IUserProcessor { /// <summary> /// 必須帶上virtual,不然無效。 /// </summary> /// <param name="user"></param> public virtual void RegUser(User user) { Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}"); } } /// <summary> /// 攔截器 /// </summary> public class MyInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { PreProceed(invocation); invocation.Proceed(); PostProceed(invocation); } public void PreProceed(IInvocation invocation) { Console.WriteLine("方法執行前"); } public void PostProceed(IInvocation invocation) { Console.WriteLine("方法執行後"); } } /// <summary> /// 運行測試 /// </summary> public static void Show() { User user = new User() { Name = "Hello", Password = "World" }; ProxyGenerator generator = new ProxyGenerator(); MyInterceptor interceptor = new MyInterceptor(); UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor); userprocessor.RegUser(user); } }
3)調用:
static void Main(string[] args) { #region 使用Castle\DynamicProxy實現動態代理 CastleProxyAOP.Show(); Console.Read(); #endregion }
4)運行結果以下:
3.2.三、使用EntLib\PIAB Unity實現AOP(非配置)
1)在NuGet中安裝Unity及Unity.Interception。
2)新建一個類:UnityAOP.cs
/// <summary> /// 使用EntLib\PIAB Unity實現動態代理(非配置) /// </summary> public class UnityAOP { #region 業務 /// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } /// <summary> /// 用戶註冊接口 /// </summary> [ExceptionHandler(Order = 1)] [LogHandler(Order = 2)] [UserHandler(Order = 3)] [AfterLogHandler(Order = 5)] public interface IUserProcessor { void RegUser(User user); } /// <summary> /// 用戶註冊接口實現類 /// </summary> public class UserProcessor : IUserProcessor //能夠不繼承MarshalByRefObject類 { public void RegUser(User user) { Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}"); } } #endregion 業務 #region 特性 /// <summary> /// 異常處理特性 /// </summary> public class ExceptionHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new ExceptionHandler() { Order = Order }; } } /// <summary> /// 日誌處理特性 /// </summary> public class LogHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new LogHandler() { Order = Order }; } } /// <summary> /// 用戶信息特性 /// </summary> public class UserHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { ICallHandler handler = new UserHandler() { Order = Order }; return handler; } } /// <summary> /// 後續日誌特性 /// </summary> public class AfterLogHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new AfterLogHandler() { Order = Order }; } } #endregion 特性 #region 特性對應的行爲 public class ExceptionHandler : ICallHandler { public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); if (methodReturn.Exception == null) { Console.WriteLine("ExceptionHandler:沒有異常"); } else { Console.WriteLine($"ExceptionHandler:出現異常:{methodReturn.Exception.Message}"); } return methodReturn; } } public class LogHandler : ICallHandler { public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { User user = input.Inputs[0] as User; string message = string.Format($"Name:{user.Name} Password:{user.Password}"); Console.WriteLine($"LogHandler:日誌已記錄。Message:{message}"); IMethodReturn methodReturn = getNext()(input, getNext); return methodReturn; } } public class UserHandler : ICallHandler { public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { User user = input.Inputs[0] as User; if (user.Password.Length < 10) { return input.CreateExceptionMethodReturn(new Exception("UserHandler:密碼長度不能小於10位")); } //getNext()(input, getNext):委託後的委託,即多重委託。 IMethodReturn methodReturn = getNext()(input, getNext); return methodReturn; } } public class AfterLogHandler : ICallHandler { public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine($"AfterLogHandler:方法執行結果--{methodReturn.ReturnValue}"); Console.WriteLine("AfterLogHandler:方法執行後"); return methodReturn; } } #endregion 特性對應的行爲 /// <summary> /// 運行測試 /// </summary> public static void Show() { User user = new User() { Name = "Hello", Password = "HelloWorld" }; IUnityContainer container = new UnityContainer(); //聲明一個容器 container.AddNewExtension<Interception>() .RegisterType<IUserProcessor, UserProcessor>(new Interceptor<TransparentProxyInterceptor>(), new InterceptionBehavior<PolicyInjectionBehavior>()); //顯式攔截 IUserProcessor processor = container.Resolve<IUserProcessor>(); processor.RegUser(user); //調用 } }
3)調用:
static void Main(string[] args) { #region 使用EntLib\PIAB Unity實現動態代理(非配置) UnityAOP.Show(); Console.Read(); #endregion }
4)運行結果以下:
3.2.四、使用EntLib\PIAB Unity實現AOP(帶配置)
1)繼續在NuGet中安裝Unity.Configuration、Unity.Interception.Configuration及Newtonsoft.Json。
2)分別創建如下類:
/// <summary> /// 用戶類 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } }
/// <summary> /// 用戶註冊接口 /// </summary> public interface IUserProcessor { void RegUser(User user); }
/// <summary> /// 用戶註冊接口實現類 /// </summary> public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine($"用戶註冊成功。Name:{user.Name} Password:{user.Password}"); } }
/// <summary> /// 使用EntLib\PIAB Unity實現動態代理(帶配置) /// </summary> public class UnityConfigAOP { public static void Show() { User user = new User() { Name = "Hello", Password = "HelloWorld" }; //配置UnityContainer IUnityContainer container = new UnityContainer(); ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap { ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"UnityConfigAOP\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); } }
/// <summary> /// 不須要特性 /// </summary> public class ExceptionBehavior : IInterceptionBehavior { public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine("ExceptionBehavior"); if (methodReturn.Exception == null) { Console.WriteLine("無異常"); } else { Console.WriteLine($"異常:{methodReturn.Exception.Message}"); } return methodReturn; } }
/// <summary> /// 不須要特性 /// </summary> public class CachingBehavior : IInterceptionBehavior { private static Dictionary<string, object> CachingBehaviorDictionary = new Dictionary<string, object>(); public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("CachingBehavior"); string key = $"{input.MethodBase.Name}_{Newtonsoft.Json.JsonConvert.SerializeObject(input.Inputs)}"; if (CachingBehaviorDictionary.ContainsKey(key)) { return input.CreateMethodReturn(CachingBehaviorDictionary[key]); //斷路器,直接返回。 } else { IMethodReturn result = getNext().Invoke(input, getNext); if (result.ReturnValue != null) CachingBehaviorDictionary.Add(key, result.ReturnValue); return result; } } }
/// <summary> /// 不須要特性 /// </summary> public class PermissionBehavior : IInterceptionBehavior { public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("PermissionBehavior"); Console.WriteLine(input.MethodBase.Name); foreach (var item in input.Inputs) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item)); //反射&序列化獲取更多信息 } return getNext().Invoke(input, getNext); } }
/// <summary> /// 不須要特性 /// </summary> public class ParameterCheckBehavior : IInterceptionBehavior { public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { User user = input.Inputs[0] as User; //能夠不寫死類型,反射+特性完成數據有效性監測。 Console.WriteLine("ParameterCheckBehavior"); if (user.Password.Length < 10) //能夠過濾一下敏感詞 { return input.CreateExceptionMethodReturn(new Exception("密碼長度不能小於10位")); } else { return getNext().Invoke(input, getNext); } } }
/// <summary> /// 不須要特性 /// </summary> public class LogBehavior : IInterceptionBehavior { public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); //執行後面的所有動做 Console.WriteLine("LogBehavior"); Console.WriteLine(input.MethodBase.Name); foreach (var item in input.Inputs) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item)); //反射&序列化獲取更多信息 } return methodReturn; } }
3)新建一個配置文件Unity.Config(本例代碼是在UnityConfigAOP文件夾下),在其屬性的複製到輸出目錄項下選擇始終複製。
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> </configSections> <unity> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/> <containers> <container name="AOPContainer"> <extension type="Interception"/> <!--註冊匹配規則:前面是完整類型名稱,後面是所在的dll名稱。--> <register type="LinkTo.Test.ConsoleAop.UnityConfigAOP.IUserProcessor,LinkTo.Test.ConsoleAop" mapTo="LinkTo.Test.ConsoleAop.UnityConfigAOP.UserProcessor,LinkTo.Test.ConsoleAop"> <interceptor type="InterfaceInterceptor"/> <!--攔截順序爲由上而下;配置會所有執行,除非遇到斷路器等;建議異常處理包在最外層,即在最上面。--> <interceptionBehavior type="LinkTo.Test.ConsoleAop.UnityConfigAOP.ExceptionBehavior, LinkTo.Test.ConsoleAop"/> <interceptionBehavior type="LinkTo.Test.ConsoleAop.UnityConfigAOP.CachingBehavior, LinkTo.Test.ConsoleAop"/> <interceptionBehavior type="LinkTo.Test.ConsoleAop.UnityConfigAOP.PermissionBehavior, LinkTo.Test.ConsoleAop"/> <interceptionBehavior type="LinkTo.Test.ConsoleAop.UnityConfigAOP.ParameterCheckBehavior, LinkTo.Test.ConsoleAop"/> <interceptionBehavior type="LinkTo.Test.ConsoleAop.UnityConfigAOP.LogBehavior, LinkTo.Test.ConsoleAop"/> </register> </container> </containers> </unity> </configuration>
4)調用:
static void Main(string[] args) { #region 使用EntLib\PIAB Unity實現動態代理(帶配置) UnityConfigAOP.UnityConfigAOP.Show(); Console.Read(); #endregion }
5)運行結果以下:
IL編織方式,可使用PostSharp框架來作,可是因爲Postsharp從2.0版本開始收費,此處再也不做說明,有興趣的話能夠百度一下。
參考自:
http://www.javashuo.com/article/p-fugdlmtx-cx.html
https://www.cnblogs.com/artech/archive/2011/12/01/autointerception.html
E神公開課代碼