.NET 下基於動態代理的 AOP 框架實現揭祕

.NET 下基於動態代理的 AOP 框架實現揭祕

Intro

以前基於 Roslyn 實現了一個簡單的條件解析引擎,想了解的能夠看這篇文章 https://www.cnblogs.com/weihanli/p/roslyn-based-condition-eval-engine.htmlhtml

執行過程當中會根據條件的不一樣會在運行時建立一個類,每一次建立都會生成一個新的程序集,我以爲這樣實現的話可能會致使加載的程序集愈來愈多,雖然目前咱們的使用場景下不會有不少,並且相同的條件只會生成一次,仍是以爲這樣不是特別好,此時想起來了一些 AOP 框架,Aspect.Core/Castle/DispatchProxy ,他們這些 AOP 框架會生成一些代碼類,好像也沒有生成不少額外的程序集,因而打算看看這些 AOP 框架的實現,看看它們是如何生成動態代理類的git

動態代理實現原理

看了這三個 AOP 框架的實現代碼以後,實現原理基本都是同樣的github

都是經過建立一個 DynamicAssembly 以後在這個 DynamicAssemly 中建立要動態生成代理類,經過 Emit 建立要生成動態代理類的方法/屬性等框架

來個小示例

多說不如來點代碼示例:ide

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 來建立代理ui

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));
}

使用示例:this

var testService = ProxyGenerator.Instance.CreateInterfaceProxy<ITestService>();
testService.Test();

能夠看到這個類型就是咱們動態建立的一個類型,輸出結果也是咱們定義在代理類中的結果spa

More

.NET 中的基於動態代理的 AOP 也是這樣實現的,實現的原理大體就是這樣,這個示例比較簡單尚未涉及 AOP ,這只是一個簡單的動態代理示例 ,AOP 只須要在原始方法執行的邏輯上包裝一層攔截器增長對攔截器的處理和調用便可,暫時還沒實現,後面有機會再分享代理

Reference

相關文章
相關標籤/搜索