.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 只需要在原始方法执行的逻辑上包装一层拦截器增加对拦截器的处理和调用即可,暂时还没实现,后面有机会再分享

(0)

相关推荐

  • jdk 动态代理源码分析

    闲来无事,撸撸源码 食用方法 直接看代码吧.. package com.test.demo.proxy;import java.lang.reflect.InvocationHandler;impor ...

  • ByxAOP——简易AOP框架

    ByxAOP是一个基于JDK动态代理的简易AOP框架,具有以下功能特性: 对目标对象的特定方法进行拦截和增强 支持灵活的拦截规则和自定义拦截规则 动态实现接口和批量实现接口方法 灵活的对象代理机制 项 ...

  • MIND - 基于动态路由的用户多向量召回

    问题背景 ▐  应用场景 在一个典型的推荐场景中,推荐算法的任务是将一个经过筛选排序的,贴近用户兴趣的商品列表推荐给用户.下面两张图片展示了手机淘宝两个比较典型的推荐场景,分别是首页的信息流场景和微详 ...

  • 审计观察 | 基于动态能力理论的基层审计机关大数据技术应用

    大数据时代的政府审计,不仅需要创新审计模式和审计方法,应对审计对象的海量数据,更需要将大数据技术手段和思维方式应用于审计流程,提供认识问题和解决问题的新思路,提升审计质量和效率.基层审计机关是政府审计 ...

  • SAP 基于 ABAP 实现的 gateway 框架里,为什么默认返回100条数据?

    Created by Wang, Jerry, last modified on Jan 16, 2015 $skip=0&$top=100 ODataListBinding.js里,this ...

  • 人物8字画法!快速画下人物动态的绝招

    画人物可能是最好的题材!但是人物很难画,因为人的形体非常复杂. 如果你有更多的时间慢慢去画,或许怎么画都可以. 但如果你面对活动的人物,要能够快速的画下来,就必须抓住要领. 经过本人多年实践经验总结, ...

  • 动手造轮子:实现一个简单的 AOP 框架

    动手造轮子:实现一个简单的 AOP 框架 Intro 最近实现了一个 AOP 框架 -- FluentAspects,API 基本稳定了,写篇文章分享一下这个 AOP 框架的设计. 整体设计 概览 I ...

  • 一文读懂Java动态代理

    引言 最早的代理模式,我们大致可以联想到三国时期,孟德君挟天子以令诸侯是代理模式,是权利代理:现今生活中类似房产中介.票务中介是代理模式,是业务代理:还有翻墙浏览网页是代理模式,是VPN代理:回到我们 ...

  • Java动态代理设计模式

    本文主要介绍Java中两种常见的动态代理方式:JDK原生动态代理和CGLIB动态代理. 什么是代理模式 就是为其他对象提供一种代理以控制对这个对象的访问.代理可以在不改动目标对象的基础上,增加其他额外 ...

  • 部署基于.netcore5.0的ABP框架后台Api服务端,以及使用Nginx部署Vue+Element前端应用

    前面介绍了很多关于ABP框架的后台Web API 服务端,以及基于Vue+Element前端应用,本篇针对两者的联合部署,以及对部署中遇到的问题进行处理.ABP框架的后端是基于.net core5.0 ...