常见的 emit 实现 AOP demo
0. 前言
上接:思想无语言边界:以 cglib 介绍 AOP 在 java 的一个实现方式
作为第四篇,我们回顾一下 csharp 里面比较常见动态编织实现方式emit
内容安排如下:
- emit aop demo
- Norns.Urd
1. emit aop demo
1.1 emit 介绍
emit 是类似 java 中ASM地位的一个底层功能实现,
不过不是转化java字节码,而是生成dotnet 的 IL代码,
生成的IL代码将由内置的JIT编译器直接编译到内存中。
官方的介绍文档
emit 对大家来说都是很熟悉的api了,动态做什么事基本都会想到它。
我们是可以使用emit 做到上篇java 的 cglib 一模一样的动态编织的AOP效果,所以语言真的只是工具,怎么玩取决于玩工具的人,demo 如下。
1.2 demo
代码
1.2.1 ProxyGenerator 简单实现
public abstract class MethodInterceptor
{
public abstract object Invoke(object instance, MethodInfo methodInfo, object[] parameters, object returnValue);
}
public static class ProxyGenerator
{
private static ModuleBuilder moduleBuilder;
private static MethodInfo getMethodMethod = typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) });
private static MethodInfo invoke = typeof(MethodInterceptor).GetMethod("Invoke");
static ProxyGenerator()
{
var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("EmitAopDemoTest"), AssemblyBuilderAccess.RunAndCollect);
moduleBuilder = asmBuilder.DefineDynamicModule("Proxy");
}
public static T Generate<T>(Type methodInterceptorType)
{
var proxyType = GenerateProxyType(typeof(T), methodInterceptorType);
return (T)Activator.CreateInstance(proxyType);
}
public static Type GenerateProxyType(Type type, Type methodInterceptorType)
{
var typeBuilder = moduleBuilder.DefineType($"{type.Name}Proxy", TypeAttributes.Class | TypeAttributes.Public, type);
foreach (var m in type.GetTypeInfo().DeclaredMethods)
{
var ps = m.GetParameters().Select(i => i.ParameterType).ToArray();
var newM = typeBuilder.DefineMethod(m.Name, MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, m.CallingConvention, m.ReturnType, ps);
CreateProxyMethod(methodInterceptorType, m, ps, newM);
typeBuilder.DefineMethodOverride(newM, m);
}
return typeBuilder.CreateType();
}
private static void CreateProxyMethod(Type methodInterceptorType, MethodInfo m, Type[] ps, MethodBuilder newM)
{
var il = newM.GetILGenerator();
var argsLocal = il.DeclareLocal(typeof(object[]));
var returnLocal = il.DeclareLocal(typeof(object));
// 初始化参数集合
il.Emit(OpCodes.Ldc_I4, ps.Length);
il.Emit(OpCodes.Newarr, typeof(object));
for (var i = 0; i < ps.Length; i++)
{
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldarg, i + 1);
il.Emit(OpCodes.Box, ps[i]);
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Stloc, argsLocal);
// 调用被代理方法
il.Emit(OpCodes.Ldarg, 0); // load this
for (var i = 0; i < ps.Length; i++)
{
il.Emit(OpCodes.Ldarg, i + 1);
}
il.Emit(OpCodes.Call, m);
il.Emit(OpCodes.Box, newM.ReturnType);
il.Emit(OpCodes.Stloc, returnLocal);
//调用方法后拦截器
il.Emit(OpCodes.Newobj, methodInterceptorType.GetConstructors().First());
il.Emit(OpCodes.Ldarg, 0); // load this
//加载方法信息参数
il.Emit(OpCodes.Ldtoken, m);
il.Emit(OpCodes.Call, getMethodMethod);
il.Emit(OpCodes.Castclass, typeof(MethodInfo));
il.Emit(OpCodes.Ldloc, argsLocal);
il.Emit(OpCodes.Ldloc, returnLocal);
il.Emit(OpCodes.Callvirt, invoke);
il.Emit(OpCodes.Stloc, returnLocal);
// return
il.Emit(OpCodes.Ldloc, returnLocal);
il.Emit(OpCodes.Unbox_Any, newM.ReturnType);
il.Emit(OpCodes.Ret);
}
}
1.2.2 Test
internal class Program
{
private static void Main(string[] args)
{
RealClass proxy = ProxyGenerator.Generate<RealClass>(typeof(AddOneInterceptor));
var i = 5;
var j = 10;
Console.WriteLine($"{i} + {j} = {(i + j)}, but proxy is {proxy.Add(i, j)}");
}
}
结果:
5 + 10 = 15, but proxy is 16
2. Norns.Urd
至此,
本系列已经介绍完了所有的aop实现方式,
以csharp 平台重点举例介绍了AOP 静态编织和动态编织 的方法。
并以 java cglib 表达了思想无编程语言边界。
最后呢,介绍一下自己正在做的项目 Norns.Urd
Github: https://github.com/fs7744/Norns.Urd
Norns.Urd 是一个基于emit实现动态代理的轻量级AOP框架.
版本基于 netstandard2.0. 所以哪些.net 版本能用你懂的。
完成这个框架的目的主要出自于个人以下意愿:
- 静态AOP和动态AOP都实现一次
- 如果不实现DI,怎么将AOP框架实现与其他现有DI框架集成
- 一个AOP 如何将 sync 和 async 方法同时兼容且如何将实现选择权完全交予用户
希望该库能对大家有些小小的作用, 开源不易,大家可以给个star 就非常nice 了
希望看过大家做码农做的开心。
常见的 emit 实现 AOP demo的更多相关文章
- Spring AOP demo 和获取被CGLIB代理的对象
本文分为两部分:1)给出Spring AOP的一个例子(会使用CGLIB代理):2)给出获取被CGLIB代理的原始对象. 1.Spring AOP Demo 这部分参考了博文(http://www.v ...
- SpringBoot配置Aop demo
1. Demo部分 package com.example.demo.controller; import org.springframework.web.bind.annotation.Reques ...
- 菜渣开源一个基于 EMIT 的 AOP 库(.NET Core)
目录 1,快速入门 1.1 继承 ActionAttribute 特性 1.2 标记代理类型 2,如何创建代理类型 2.1 通过API直接创建 2,创建代理类型 通过API 通过 Microsoft. ...
- Spring Boot AOP Demo
什么是AOP? AOP面向切面,切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性. 实现策略JAVA SE动态代理 ...
- Spring学习03——AOP Demo
切面类StudentServiceAspect.java package com.su.advice; import org.aspectj.lang.JoinPoint; import org.as ...
- C#利用Emit反射实现AOP,以及平台化框架封装思路
C#利用Emit反射实现AOP,以及平台化框架封装思路 这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路. 首先是主函数 ...
- .Net Core下基于Emit的打造AOP
之前的基于DispatchProxy的AOP组件,实现了属性注入,但是这个依旧有很多限制 比如不支持构造器注入,继承DispatchProxy的子类必须是公开类 个人有点代码洁癖,不喜欢这种不能控制的 ...
- Spring IOC及AOP学习总结
一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.还有一类是ApplicationContext.BeanFactory提供了基础的容器功能.Appl ...
- SpringBoot基础篇AOP之基本使用姿势小结
一般来讲,谈到Spring的特性,绕不过去的就是DI(依赖注入)和AOP(切面),在将bean的系列中,说了DI的多种使用姿势:接下来看一下AOP的玩法 <!-- more --> I. ...
随机推荐
- RSA脚本环境配置-攻防世界-OldDriver
[Crypto] 题目链接 [RSA算法解密] 审题分析 首先拿到一个压缩包,解压得到文件enc.txt. 先不用去管其他,第一眼enc马上联想到 RSA解密.接着往下看 [{"c" ...
- Druid配置和初始化参数 转发地址图片有
配置数据源 1.添加上 Druid 数据源依赖. <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dep ...
- 利用css3和js实现旋转木马图片小demo
先看效果图: 上源码 html代码 <!DOCTYPE html> <html lang="en"> <head> <meta chars ...
- yii2.0验证码的两种实现方式
第一种方式:采用model 1. 模型:Code.php <?phpnamespace app\models; use yii\base\Model;class Code extends Mod ...
- 【CF983C】elevator——记忆化搜索
(题面来自luogu) 题意翻译 题意 一个9层的楼有一个可以容纳4个人的电梯,你要管理这个电梯. 现在各层楼上有一些在排队的人,你知道他们在哪层要到哪层去.你也知道到电梯门口的顺序.根据公司的规定, ...
- 通过Apache Hudi和Alluxio建设高性能数据湖
T3出行的杨华和张永旭描述了他们数据湖架构的发展.该架构使用了众多开源技术,包括Apache Hudi和Alluxio.在本文中,您将看到我们如何使用Hudi和Alluxio将数据摄取时间缩短一半.此 ...
- moviepy音视频剪辑:视频剪辑基类VideoClip的__init__构造方法参数has_constant_size的作用
☞ ░ 前往老猿Python博文目录 ░ moviepy音视频剪辑模块的视频剪辑基类VideoClip构造方法: __init__(self, make_frame=None, ismask=Fals ...
- PyQt(Python+Qt)学习随笔:QTableWidget的属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.概述 除了从父类继承的属性外,在Designer中QTableWidget只有两个属性,就是行数 ...
- PyQt(Python+Qt)学习随笔:QTreeView树形视图的rootIsDecorated属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.属性说明 QTreeView树形视图的rootIsDecorated属性用于控制是否展示对顶层项 ...
- PyQt(Python+Qt)学习随笔:QTableView的cornerButtonEnabled属性
老猿Python博文目录 老猿Python博客地址 cornerButtonEnabled属性用于控制是否启用左上角的按钮.如果此属性为True,则启用视图左上角的按钮,单击此按钮将选择表视图中的所有 ...