.NET 下基於動態代理的 AOP 框架實現揭秘 Intro 之前基於 Roslyn 實現了一個簡單的條件解析引擎,想瞭解的可以看這篇文章 執行過程中會根據條件的不同會在運行時創建一個類,每一次創建都會生成一個新的程式集,我覺得這樣實現的話可能會導致載入的程式集越來越多,雖然目前我們的使用場景下不會 ...
.NET 下基於動態代理的 AOP 框架實現揭秘
Intro
之前基於 Roslyn 實現了一個簡單的條件解析引擎,想瞭解的可以看這篇文章 https://www.cnblogs.com/weihanli/p/roslyn-based-condition-eval-engine.html
執行過程中會根據條件的不同會在運行時創建一個類,每一次創建都會生成一個新的程式集,我覺得這樣實現的話可能會導致載入的程式集越來越多,雖然目前我們的使用場景下不會有很多,而且相同的條件只會生成一次,還是覺得這樣不是特別好,此時想起來了一些 AOP 框架,Aspect.Core
/Castle
/DispatchProxy
,他們這些 AOP 框架會生成一些代碼類,好像也沒有生成很多額外的程式集,於是打算看看這些 AOP 框架的實現,看看它們是如何生成動態代理類的
動態代理實現原理
看了這三個 AOP 框架的實現代碼之後,實現原理基本都是一樣的
都是通過創建一個 DynamicAssembly
之後在這個 DynamicAssemly
中創建要動態生成代理類,通過 Emit 創建要生成動態代理類的方法/屬性等
來個小示例
多說不如來點代碼示例:
internal class ProxyUtil
{
private const string ProxyAssemblyName = "Aop.DynamicGenerated";
private static readonly ModuleBuilder _moduleBuilder;
private static readonly ConcurrentDictionary<string, Type> _proxyTypes = new ConcurrentDictionary<string, Type>();
static ProxyUtil()
{
// 定義一個動態程式集
var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(ProxyAssemblyName), AssemblyBuilderAccess.Run);
// 創建一個動態模塊,後面創建動態代理類通過這個來創建
_moduleBuilder = asmBuilder.DefineDynamicModule("Default");
}
public static Type CreateInterfaceProxy(Type interfaceType)
{
var proxyTypeName = $"{ProxyAssemblyName}.{interfaceType.FullName}";
var type = _proxyTypes.GetOrAdd(proxyTypeName, name =>
{
// 定義要創建的類型,並實現指定類型介面
var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Public, typeof(object), new[] { interfaceType });
// 定義一個預設的構造方法
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// 獲取介面中定義的方法
var methods = interfaceType.GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach (var method in methods)
{
// 在動態類中定義方法,方法名稱,返回值和簽名與介面方法保持一致
var methodBuilder = typeBuilder.DefineMethod(method.Name
, MethodAttributes.Public | MethodAttributes.Virtual,
method.CallingConvention,
method.ReturnType,
method.GetParameters()
.Select(p => p.ParameterType)
.ToArray()
);
// 獲取 ILGenerator,通過 Emit 實現方法體
var ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.EmitWriteLine($"method [{method.Name}] is invoking...");
ilGenerator.Emit(OpCodes.Ret);
// 定義方法實現
typeBuilder.DefineMethodOverride(methodBuilder, method);
}
return typeBuilder.CreateType();
});
return type;
}
}
通過上面的定義我們可以創建一個簡單的代理類,然後定義一個 ProxyGenerator
來創建代理
public class ProxyGenerator
{
public static readonly ProxyGenerator Instance = new ProxyGenerator();
public object CreateInterfaceProxy(Type interfaceType)
{
var type = ProxyUtil.CreateInterfaceProxy(interfaceType);
return Activator.CreateInstance(type);
}
}
// 定義泛型擴展
public static class ProxyGeneratorExtensions
{
public static TInterface CreateInterfaceProxy<TInterface>(this ProxyGenerator proxyGenerator) =>
(TInterface)proxyGenerator.CreateInterfaceProxy(typeof(TInterface));
}
使用示例:
var testService = ProxyGenerator.Instance.CreateInterfaceProxy<ITestService>();
testService.Test();
可以看到這個類型就是我們動態創建的一個類型,輸出結果也是我們定義在代理類中的結果
More
.NET 中的基於動態代理的 AOP 也是這樣實現的,實現的原理大致就是這樣,這個示例比較簡單還沒有涉及 AOP ,這隻是一個簡單的動態代理示例 ,AOP 只需要在原始方法執行的邏輯上包裝一層攔截器增加對攔截器的處理和調用即可,暫時還沒實現,後面有機會再分享
Reference
- https://github.com/dotnetcore/AspectCore-Framework
- https://github.com/dotnetcore/AspectCore-Framework/blob/master/src/AspectCore.Core/Utils/ProxyGeneratorUtils.cs
- https://github.com/castleproject/Core
- https://github.com/castleproject/Core/blob/master/src/Castle.Core/DynamicProxy/ModuleScope.cs
- https://github.com/dotnet/runtime/blob/master/src/libraries/System.Reflection.DispatchProxy/src/System/Reflection/DispatchProxyGenerator.cs
- https://github.com/WeihanLi/SamplesInPractice/blob/master/AopSample/Program.cs