本章將簡單介紹下AOP面向切面編程。首先咱們先來看些概念。html
POP面向過程編程:符合邏輯思惟,線性的處理問題-----沒法應付複雜的系統。編程
OOP面向對象編程:設計模式
萬物皆對象,對象交互完成功能,功能疊加成模塊,模塊組成系統,去搭建複雜的大型軟件系統。緩存
類倒是會變化的,增長日誌/異常/權限/緩存/事務,只能修改類?app
只能替換整個對象,沒辦法把一個類動態改變。框架
GOF的23種設計模式,應對變化,核心套路是依賴抽象,細節就能夠變化。工具
AOP面向切面編程:性能
是一種編程思想,是OOP思想的補充。ui
容許開發者動態的修改靜態的OO模型,就像現實生活中對象在生命週期中會不斷的改變自身。 this
正是由於可以動態的擴展功能,因此在程序設計時就能夠有如下好處:
一、只須要聚焦核心業務邏輯,權限/異常/日誌/緩存/事務等通用功能能夠經過AOP方式添加,使程序設計變得更加簡單。
二、功能動態擴展;集中管理;代碼複用;規範化;
實現AOP的多種方式:
一、靜態實現---裝飾器模式/代理模式。
二、動態實現---Remoting/Castle(Emit)
三、靜態織入---PostSharp(收費)---擴展編譯工具,生成的加入額外代碼。
四、依賴注入容器的AOP擴展(開發)
五、MVC的Filter---特性標記,而後該方法執行前/後就多了邏輯。
下面看一張圖來輔助咱們瞭解:
從圖中一刀切過去將核心業務邏輯和咱們的通用功能分離,這樣的話咱們只須要聚焦核心業務邏輯,而權限/異常/日誌/緩存/事務等通用功能能夠經過AOP方式添加,使程序設計變得更加簡單。
下面咱們重點來看下代碼如何實現,爲了演示此處咱們使用VS2017建個控制檯項目MyAOP,目標框架爲:.NET Framework 4.6.1,以下所示:
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()的結果:
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()的結果:
首先來看下項目的目錄結構:
須要從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