.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

.NET 下基于动态代理的 AOP 框架实现揭秘的更多相关文章

  1. 实现一个简单的基于动态代理的 AOP

    实现一个简单的基于动态代理的 AOP Intro 上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了 目前的实现是基于 Emit 来做的, ...

  2. 动态代理到基于动态代理的AOP

    动态代理,是java支持的一种程序设计方法. 动态代理实现中有两个重要的接口和类,分别是InvocationHandler(interface),Proxy(class). 要实现动态代理,必须要定义 ...

  3. .Net 框架实现AOP(动态代理实现AOP,本文为翻译)

    在上一节,我们将静态实现AOP,但是对于一个大型项目,要想为每个类,每个方法都去实现AOP ,进行日志记录和权限验证似乎是不可能的. 即使可能对于成百上千个类维护,也是很难维护.所以今天的主题就是如标 ...

  4. 动态代理的两种方式,以及区别(静态代理、JDK与CGLIB动态代理、AOP+IoC)

    Spring学习总结(二)——静态代理.JDK与CGLIB动态代理.AOP+IoC   目录 一.为什么需要代理模式 二.静态代理 三.动态代理,使用JDK内置的Proxy实现 四.动态代理,使用cg ...

  5. Java动态代理-->Spring AOP

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Jav ...

  6. Java 动态代理与AOP

    动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy),并由代理对象控制对target对象的引用. 模式图: 代理模式中的角色有: 抽象对象角色(Abstrac ...

  7. Java 动态代理及AOP实现机制

    AOP实现机制http://www.iteye.com/topic/1116696 AOP: (Aspect Oriented Programming) 面向切面编程AOP包括切面(aspect).通 ...

  8. DispatchProxy实现动态代理及AOP

    DispatchProxy类是DotnetCore下的动态代理的类,源码地址:Github,官方文档:MSDN.主要是Activator以及AssemblyBuilder来实现的(请看源码分析),园子 ...

  9. Java-JDK动态代理(AOP)使用及实现原理分析

    Java-JDK动态代理(AOP)使用及实现原理分析 第一章:代理的介绍 介绍:我们需要掌握的程度 动态代理(理解) 基于反射机制 掌握的程度: 1.什么是动态代理? 2.动态代理能够做什么? 后面我 ...

随机推荐

  1. 蓝桥杯vip题阶乘计算

    蓝桥杯vip题阶乘计算 详细题目 输入一个正整数n,输出n!的值. 其中n!=123*-*n. 算法描述 n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法.使用一个数组A来表示一个 ...

  2. 在eclipse里面给maven项目打包

    eclipse中的“maven install”是用maven打包工程的意思. mvn install 是将用户打包好的jar包安装到本地仓库中,一般没有设置过的话默认在用户目录下的 .m2\下面. ...

  3. 简述UDF/UDAF/UDTF是什么,各自解决问题及应用场景

    UDF User-Defined-Function 自定义函数 .一进一出: 背景 系统内置函数无法解决实际的业务问题,需要开发者自己编写函数实现自身的业务实现诉求. 应用场景非常多,面临的业务不同导 ...

  4. 2020年PHP 面试问题(二)

    一.什么是 CGI?什么是 FastCGI?php-fpm,FastCGI,Nginx 之间是什么关系? CGI,通用网关接口,用于WEB服务器和应用程序间的交互,定义输入输出规范,用户的请求通过WE ...

  5. 【转】Standardization(标准化)和Normalization(归一化)的区别

    Standardization(标准化)和Normalization(归一化)的区别  https://blog.csdn.net/Dhuang159/article/details/83627146 ...

  6. Transformers 词汇表 | 二

    作者|huggingface 编译|VK 来源|Github 词汇表每种模型都不同,但与其他模型相似.因此,大多数模型使用相同的输入,此处将在用法示例中进行详细说明. 输入ID 输入id通常是传递给模 ...

  7. 累加数的贡献 CodeForces - 1213D2

    题意: 第一行输入n,k,表示有n个数,可以进行整除2操作,要是数组有k个相等的数,最少需要几次操作. 思路: 用一个数组记录每一个数出现的次数,如果一开始大于等于k,直接输出0,否则对这n个数进行从 ...

  8. Golang校招简历项目-简单的分布式缓存

    前言 前段时间,校招投了golang岗位,但是没什么好的项目往简历上写,于是参考了许多网上资料,做了一个简单的分布式缓存项目. 现在闲下来了,打算整理下. github项目地址:https://git ...

  9. 一些数组笔记(C)

    0.数组名是一个指针,存放数组首元素地址,所以使用scanf()接受字符串输入时只用写上数组名,不用加&.数组名是常量不允许修改其值.数组只能定义的时候初始化,后期初始化会被认为是修改数组名的 ...

  10. swagger2 接口文档,整个微服务接口文档

    1,因为整个微服务会有好多服务,比如会员服务,支付服务,订单服务,每个服务都集成了swagger 我们在访问的时候,不可能每个服务输入一个url 去访问,看起来很麻烦,所以我们需要在一个页面上集成整个 ...