本章将簡單介紹下AOP面向切面程式設計。
本章将簡單介紹下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
版權聲明:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!