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 简单实现

  1. public abstract class MethodInterceptor
  2. {
  3. public abstract object Invoke(object instance, MethodInfo methodInfo, object[] parameters, object returnValue);
  4. }
  5. 
  6. public static class ProxyGenerator
  7. {
  8. private static ModuleBuilder moduleBuilder;
  9. private static MethodInfo getMethodMethod = typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) });
  10. private static MethodInfo invoke = typeof(MethodInterceptor).GetMethod("Invoke");
  11. static ProxyGenerator()
  12. {
  13. var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("EmitAopDemoTest"), AssemblyBuilderAccess.RunAndCollect);
  14. moduleBuilder = asmBuilder.DefineDynamicModule("Proxy");
  15. }
  16. public static T Generate<T>(Type methodInterceptorType)
  17. {
  18. var proxyType = GenerateProxyType(typeof(T), methodInterceptorType);
  19. return (T)Activator.CreateInstance(proxyType);
  20. }
  21. public static Type GenerateProxyType(Type type, Type methodInterceptorType)
  22. {
  23. var typeBuilder = moduleBuilder.DefineType($"{type.Name}Proxy", TypeAttributes.Class | TypeAttributes.Public, type);
  24. foreach (var m in type.GetTypeInfo().DeclaredMethods)
  25. {
  26. var ps = m.GetParameters().Select(i => i.ParameterType).ToArray();
  27. var newM = typeBuilder.DefineMethod(m.Name, MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, m.CallingConvention, m.ReturnType, ps);
  28. CreateProxyMethod(methodInterceptorType, m, ps, newM);
  29. typeBuilder.DefineMethodOverride(newM, m);
  30. }
  31. return typeBuilder.CreateType();
  32. }
  33. private static void CreateProxyMethod(Type methodInterceptorType, MethodInfo m, Type[] ps, MethodBuilder newM)
  34. {
  35. var il = newM.GetILGenerator();
  36. var argsLocal = il.DeclareLocal(typeof(object[]));
  37. var returnLocal = il.DeclareLocal(typeof(object));
  38. // 初始化参数集合
  39. il.Emit(OpCodes.Ldc_I4, ps.Length);
  40. il.Emit(OpCodes.Newarr, typeof(object));
  41. for (var i = 0; i < ps.Length; i++)
  42. {
  43. il.Emit(OpCodes.Dup);
  44. il.Emit(OpCodes.Ldc_I4, i);
  45. il.Emit(OpCodes.Ldarg, i + 1);
  46. il.Emit(OpCodes.Box, ps[i]);
  47. il.Emit(OpCodes.Stelem_Ref);
  48. }
  49. il.Emit(OpCodes.Stloc, argsLocal);
  50. // 调用被代理方法
  51. il.Emit(OpCodes.Ldarg, 0); // load this
  52. for (var i = 0; i < ps.Length; i++)
  53. {
  54. il.Emit(OpCodes.Ldarg, i + 1);
  55. }
  56. il.Emit(OpCodes.Call, m);
  57. il.Emit(OpCodes.Box, newM.ReturnType);
  58. il.Emit(OpCodes.Stloc, returnLocal);
  59. //调用方法后拦截器
  60. il.Emit(OpCodes.Newobj, methodInterceptorType.GetConstructors().First());
  61. il.Emit(OpCodes.Ldarg, 0); // load this
  62. //加载方法信息参数
  63. il.Emit(OpCodes.Ldtoken, m);
  64. il.Emit(OpCodes.Call, getMethodMethod);
  65. il.Emit(OpCodes.Castclass, typeof(MethodInfo));
  66. il.Emit(OpCodes.Ldloc, argsLocal);
  67. il.Emit(OpCodes.Ldloc, returnLocal);
  68. il.Emit(OpCodes.Callvirt, invoke);
  69. il.Emit(OpCodes.Stloc, returnLocal);
  70. // return
  71. il.Emit(OpCodes.Ldloc, returnLocal);
  72. il.Emit(OpCodes.Unbox_Any, newM.ReturnType);
  73. il.Emit(OpCodes.Ret);
  74. }
  75. }

1.2.2 Test

  1. internal class Program
  2. {
  3. private static void Main(string[] args)
  4. {
  5. RealClass proxy = ProxyGenerator.Generate<RealClass>(typeof(AddOneInterceptor));
  6. var i = 5;
  7. var j = 10;
  8. Console.WriteLine($"{i} + {j} = {(i + j)}, but proxy is {proxy.Add(i, j)}");
  9. }
  10. }

结果:

  1. 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的更多相关文章

  1. Spring AOP demo 和获取被CGLIB代理的对象

    本文分为两部分:1)给出Spring AOP的一个例子(会使用CGLIB代理):2)给出获取被CGLIB代理的原始对象. 1.Spring AOP Demo 这部分参考了博文(http://www.v ...

  2. SpringBoot配置Aop demo

    1. Demo部分 package com.example.demo.controller; import org.springframework.web.bind.annotation.Reques ...

  3. 菜渣开源一个基于 EMIT 的 AOP 库(.NET Core)

    目录 1,快速入门 1.1 继承 ActionAttribute 特性 1.2 标记代理类型 2,如何创建代理类型 2.1 通过API直接创建 2,创建代理类型 通过API 通过 Microsoft. ...

  4. Spring Boot AOP Demo

    什么是AOP? AOP面向切面,切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性. 实现策略JAVA SE动态代理 ...

  5. Spring学习03——AOP Demo

    切面类StudentServiceAspect.java package com.su.advice; import org.aspectj.lang.JoinPoint; import org.as ...

  6. C#利用Emit反射实现AOP,以及平台化框架封装思路

    C#利用Emit反射实现AOP,以及平台化框架封装思路 这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路. 首先是主函数 ...

  7. .Net Core下基于Emit的打造AOP

    之前的基于DispatchProxy的AOP组件,实现了属性注入,但是这个依旧有很多限制 比如不支持构造器注入,继承DispatchProxy的子类必须是公开类 个人有点代码洁癖,不喜欢这种不能控制的 ...

  8. Spring IOC及AOP学习总结

    一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.还有一类是ApplicationContext.BeanFactory提供了基础的容器功能.Appl ...

  9. SpringBoot基础篇AOP之基本使用姿势小结

    一般来讲,谈到Spring的特性,绕不过去的就是DI(依赖注入)和AOP(切面),在将bean的系列中,说了DI的多种使用姿势:接下来看一下AOP的玩法 <!-- more --> I. ...

随机推荐

  1. SD卡被格式化了还能恢复吗

    SD卡轻便小巧,它的主要功能是拓展便携式设备.包括:数据相机.手机及其他的多媒体播放器等的存储空间,缓解设备本身的存储压力. 很多用户反应,SD卡使用了一定的时间后,会出现SD卡受损的提示,再次打开的 ...

  2. mathtype样式系统使用技巧-通过样式定义来更改方程中的字体

    本教程中,我们主要介绍MathType Desktop的样式系统.演示如何通过更改样式定义来更改方程中的字体.通过样式可以快速轻松地实现我们所需的公式格式,并统一所有公式的样式. 我们以如下公式来作为 ...

  3. vulnhub: DC 3

    通过nmap扫描,只开放了80端口,并且该web服务是基于Joomla搭建: root@kali:~# nmap -A 192.168.74.140 Starting Nmap 7.80 ( http ...

  4. houdini 鱼眼相机

    http://mattebb.com/weblog/houdini-fisheye-camera/ 这个网站是有提供一个相机shader的,,如图是方形的,国内的用户,比较多是做球幕的小伙伴,圆形就行 ...

  5. PADS生成贴片文件

    PADS生成贴片文件 VIEW-BOTTOM VIEW能够使Bottom层正常显示. 1. pastmask_top->Output Devices->Device Setup- 2. 进 ...

  6. 小样本学习最新综述 A Survey on Few-shot Learning | Introduction and Overview

    目录 01 Introduction Bridging this gap between AI and humans is an important direction. FSL can also h ...

  7. springboot补充

    springboot中的日志: 在默认的spring-boot-starter中,会引入spring-boot-starter-logging, 而springboot-starte-longing中 ...

  8. 基于ARM64的Qemu/KVM学习环境搭建

    作者:pengdonglin137@163.com 在没有aarch64架构的开发板的情况下,可以使用Qemu来模拟一个支持KVM的AArch64位的host,然后再在其上运行一个开启KVM加速的Qe ...

  9. 第7.12节 可共享的Python类变量

    第7.12节 可共享的Python类变量 一.    引言 在上节已经引入介绍了类变量和实例变量,类体中定义的变量为类变量,默认属于类本身,实例变量是实例方法中定义的self对象的变量,对于每个实例都 ...

  10. 第三十八章、PyQt输入部件:QKeySequenceEdit快捷键输入部件使用案例

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.功能简介 Key Sequence Edit输 ...