• .net 使用IL生成代理类实现AOP对比Java Spring Boot的AOP


    首先,我们需要定义一个接口,代表我们要代理的目标对象的功能:

    1. // 日志记录器接口
    2. public interface ILogger
    3. {
    4. ///
    5. /// 记录日志
    6. ///
    7. /// 日志消息
    8. void Log(string message);
    9. }
    10. // 日志记录器实现类
    11. public class Logger : ILogger
    12. {
    13. public void Log(string message)
    14. {
    15. Console.WriteLine($"Logging: {message}");
    16. }
    17. }

    然后,我们创建一个代理类,实现该接口,并在目标方法的执行前后注入额外的逻辑:

    1. // 切面接口
    2. public interface IInterceptor
    3. {
    4. ///
    5. /// 在方法执行前执行的逻辑
    6. ///
    7. /// 目标类型
    8. /// 方法名称
    9. void BeforeMethod(Type targetType, string methodName);
    10. ///
    11. /// 在方法执行后执行的逻辑
    12. ///
    13. /// 目标类型
    14. /// 方法名称
    15. void AfterMethod(Type targetType, string methodName);
    16. }
    17. // 日志记录切面类
    18. public class LoggingAspect : IInterceptor
    19. {
    20. public void BeforeMethod(Type targetType, string methodName)
    21. {
    22. Console.WriteLine($"Before {targetType.Name}.{methodName}");
    23. }
    24. public void AfterMethod(Type targetType, string methodName)
    25. {
    26. Console.WriteLine($"After {targetType.Name}.{methodName}");
    27. }
    28. }

    接下来,我们通过使用IL生成代理类型的字节码,动态创建代理对象:

    1. // 代理生成器
    2. public static class ProxyGenerator
    3. {
    4. ///
    5. /// 创建代理对象
    6. ///
    7. /// 目标接口类型
    8. /// 目标对象实例
    9. /// 切面对象实例
    10. /// 代理对象
    11. public static TInterface CreateProxy<TInterface>(TInterface target, IInterceptor interceptor)
    12. where TInterface : class
    13. {
    14. Type targetType = typeof(TInterface);
    15. TypeBuilder typeBuilder = CreateTypeBuilder(targetType);
    16. ImplementInterface(typeBuilder, targetType);
    17. ImplementMethods(typeBuilder, targetType, interceptor);
    18. Type proxyType = typeBuilder.CreateType();
    19. return Activator.CreateInstance(proxyType, target, interceptor) as TInterface;
    20. }
    21. private static TypeBuilder CreateTypeBuilder(Type targetType)
    22. {
    23. string typeName = targetType.Name + "Proxy";
    24. AssemblyName assemblyName = new AssemblyName(typeName);
    25. AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    26. ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(typeName + "Module");
    27. TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
    28. typeBuilder.AddInterfaceImplementation(targetType);
    29. return typeBuilder;
    30. }
    31. private static void ImplementInterface(TypeBuilder typeBuilder, Type targetType)
    32. {
    33. foreach (MethodInfo method in targetType.GetMethods())
    34. {
    35. Type[] parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
    36. MethodBuilder methodBuilder = typeBuilder.DefineMethod(
    37. method.Name,
    38. MethodAttributes.Public | MethodAttributes.Virtual,
    39. method.ReturnType,
    40. parameterTypes
    41. );
    42. typeBuilder.DefineMethodOverride(methodBuilder, method);
    43. }
    44. }
    45. private static void ImplementMethods(TypeBuilder typeBuilder, Type targetType, IInterceptor interceptor)
    46. {
    47. foreach (MethodInfo method in targetType.GetMethods())
    48. {
    49. MethodBuilder methodBuilder = typeBuilder.GetMethod(method.Name).GetBaseDefinition() as MethodBuilder;
    50. if (methodBuilder != null)
    51. {
    52. ILGenerator ilGenerator = methodBuilder.GetILGenerator();
    53. // 调用切面方法
    54. ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
    55. ilGenerator.Emit(OpCodes.Ldfld, typeBuilder.GetField("interceptor")); // 加载interceptor到堆栈
    56. ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
    57. ilGenerator.Emit(OpCodes.Ldtoken, targetType); // 加载targetType到堆栈
    58. ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // 调用GetTypeFromHandle方法
    59. ilGenerator.Emit(OpCodes.Ldstr, method.Name); // 加载方法名到堆栈
    60. ilGenerator.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("BeforeMethod")); // 调用BeforeMethod方法
    61. ilGenerator.Emit(OpCodes.Pop); // 丢弃返回值
    62. // 调用目标方法
    63. ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
    64. for (int i = 1; i <= method.GetParameters().Length; i++)
    65. {
    66. ilGenerator.Emit(OpCodes.Ldarg_S, i); // 加载方法参数到堆栈
    67. }
    68. ilGenerator.Emit(OpCodes.Callvirt, targetType.GetMethod(method.Name)); // 调用目标方法
    69. // 调用切面方法
    70. ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
    71. ilGenerator.Emit(OpCodes.Ldfld, typeBuilder.GetField("interceptor")); // 加载interceptor到堆栈
    72. ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
    73. ilGenerator.Emit(OpCodes.Ldtoken, targetType); // 加载targetType到堆栈
    74. ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // 调用GetTypeFromHandle方法
    75. ilGenerator.Emit(OpCodes.Ldstr, method.Name); // 加载方法名到堆栈
    76. ilGenerator.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("AfterMethod")); // 调用AfterMethod方法
    77. ilGenerator.Emit(OpCodes.Pop); // 丢弃返回值
    78. }
    79. }
    80. }
    81. }

    最后,我们可以使用以下代码来测试动态代理的功能:

    1. class Program
    2. {
    3. static void Main(string[] args)
    4. {
    5. // 创建目标对象
    6. ILogger logger = new Logger();
    7. // 创建切面对象
    8. IInterceptor interceptor = new LoggingAspect();
    9. // 创建代理对象
    10. ILogger proxy = ProxyGenerator.CreateProxy(logger, interceptor);
    11. // 调用代理对象的方法
    12. proxy.Log("Hello, World!");
    13. Console.ReadLine();
    14. }
    15. }

    对比一下Java Spring Boot 的AOP

    1. 动态代理实现方式:在Java Spring Boot中,基于代理的AOP主要使用JDK动态代理和CGLIB代理来实现。而在C#中,使用IL生成器(ILGenerator)直接操作IL指令来生成和修改类型的字节码,实现动态代理。这种方式相对于代理类的生成更加底层,需要对CLR(Common Language Runtime)和IL指令有一定的了解。

    2. IL的语法和特性:IL是.NET平台的中间语言,类似于汇编语言,但具有一些.NET特定的语法和特性。IL指令用于描述类型、方法、属性等的结构和操作,需要了解这些指令的使用规则和约束。相比之下,Java字节码(Java bytecode)是Java虚拟机(JVM)上的中间语言,其语法和特性与IL有所不同。

    3. 第三方库和框架:在Java生态系统中,有许多第三方库和框架(如AspectJ、Spring AOP)提供了高级别的API和工具,使AOP的使用更加方便。而在C#中,虽然也有一些库(如Castle DynamicProxy、Unity Interception)可以辅助实现AOP,但相对于Java生态系统来说,可选择的工具和框架较少

      综上所述,C#使用IL实现AOP与Java Spring Boot的AOP在实现方式、编程语言和生态系统等方面存在一些不同。C#开发者需要直接操作IL指令来生成和修改类型的字节码,需要对CLR和IL指令有一定的了解。而Java Spring Boot的AOP则基于代理实现,使用注解和切点表达式等高级别的API来配置和管理AOP。

  • 相关阅读:
    理解Java程序的执行
    高速数据采集与图像传输对带宽需求的对比分析
    Java竞赛快速输入输出,防止读取数据过慢导致超时
    【Django】开发日报_10_Day:手机号码管理系统(8)
    3DTiles 1.0 数据规范详解[4.1] b3dm瓦片二进制数据文件结构
    使用win_b64做CATIA的开发测试
    适配器模式:类适配器模式 对象适配器模式 详细讲解
    JDK核心JAVA源码解析(8) - 自动封箱拆箱与效率的思考
    awtk-ftpd 发布
    Java代码审计rce漏洞
  • 原文地址:https://blog.csdn.net/lee576/article/details/133265889