首先,我们需要定义一个接口,代表我们要代理的目标对象的功能:
// 日志记录器接口
public interface ILogger
{
/// <summary>
/// 记录日志
/// </summary>
/// <param name="message">日志消息</param>
void Log(string message);
}
// 日志记录器实现类
public class Logger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"Logging: {message}");
}
}
然后,我们创建一个代理类,实现该接口,并在目标方法的执行前后注入额外的逻辑:
// 切面接口
public interface IInterceptor
{
/// <summary>
/// 在方法执行前执行的逻辑
/// </summary>
/// <param name="targetType">目标类型</param>
/// <param name="methodName">方法名称</param>
void BeforeMethod(Type targetType, string methodName);
/// <summary>
/// 在方法执行后执行的逻辑
/// </summary>
/// <param name="targetType">目标类型</param>
/// <param name="methodName">方法名称</param>
void AfterMethod(Type targetType, string methodName);
}
// 日志记录切面类
public class LoggingAspect : IInterceptor
{
public void BeforeMethod(Type targetType, string methodName)
{
Console.WriteLine($"Before {targetType.Name}.{methodName}");
}
public void AfterMethod(Type targetType, string methodName)
{
Console.WriteLine($"After {targetType.Name}.{methodName}");
}
}
接下来,我们通过使用IL生成代理类型的字节码,动态创建代理对象:
// 代理生成器
public static class ProxyGenerator
{
/// <summary>
/// 创建代理对象
/// </summary>
/// <typeparam name="TInterface">目标接口类型</typeparam>
/// <param name="target">目标对象实例</param>
/// <param name="interceptor">切面对象实例</param>
/// <returns>代理对象</returns>
public static TInterface CreateProxy<TInterface>(TInterface target, IInterceptor interceptor)
where TInterface : class
{
Type targetType = typeof(TInterface);
TypeBuilder typeBuilder = CreateTypeBuilder(targetType);
ImplementInterface(typeBuilder, targetType);
ImplementMethods(typeBuilder, targetType, interceptor);
Type proxyType = typeBuilder.CreateType();
return Activator.CreateInstance(proxyType, target, interceptor) as TInterface;
}
private static TypeBuilder CreateTypeBuilder(Type targetType)
{
string typeName = targetType.Name + "Proxy";
AssemblyName assemblyName = new AssemblyName(typeName);
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(typeName + "Module");
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
typeBuilder.AddInterfaceImplementation(targetType);
return typeBuilder;
}
private static void ImplementInterface(TypeBuilder typeBuilder, Type targetType)
{
foreach (MethodInfo method in targetType.GetMethods())
{
Type[] parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
method.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
method.ReturnType,
parameterTypes
);
typeBuilder.DefineMethodOverride(methodBuilder, method);
}
}
private static void ImplementMethods(TypeBuilder typeBuilder, Type targetType, IInterceptor interceptor)
{
foreach (MethodInfo method in targetType.GetMethods())
{
MethodBuilder methodBuilder = typeBuilder.GetMethod(method.Name).GetBaseDefinition() as MethodBuilder;
if (methodBuilder != null)
{
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
// 调用切面方法
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
ilGenerator.Emit(OpCodes.Ldfld, typeBuilder.GetField("interceptor")); // 加载interceptor到堆栈
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
ilGenerator.Emit(OpCodes.Ldtoken, targetType); // 加载targetType到堆栈
ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // 调用GetTypeFromHandle方法
ilGenerator.Emit(OpCodes.Ldstr, method.Name); // 加载方法名到堆栈
ilGenerator.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("BeforeMethod")); // 调用BeforeMethod方法
ilGenerator.Emit(OpCodes.Pop); // 丢弃返回值
// 调用目标方法
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
for (int i = 1; i <= method.GetParameters().Length; i++)
{
ilGenerator.Emit(OpCodes.Ldarg_S, i); // 加载方法参数到堆栈
}
ilGenerator.Emit(OpCodes.Callvirt, targetType.GetMethod(method.Name)); // 调用目标方法
// 调用切面方法
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
ilGenerator.Emit(OpCodes.Ldfld, typeBuilder.GetField("interceptor")); // 加载interceptor到堆栈
ilGenerator.Emit(OpCodes.Ldarg_0); // 加载this到堆栈
ilGenerator.Emit(OpCodes.Ldtoken, targetType); // 加载targetType到堆栈
ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); // 调用GetTypeFromHandle方法
ilGenerator.Emit(OpCodes.Ldstr, method.Name); // 加载方法名到堆栈
ilGenerator.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("AfterMethod")); // 调用AfterMethod方法
ilGenerator.Emit(OpCodes.Pop); // 丢弃返回值
}
}
}
}
最后,我们可以使用以下代码来测试动态代理的功能:
class Program
{
static void Main(string[] args)
{
// 创建目标对象
ILogger logger = new Logger();
// 创建切面对象
IInterceptor interceptor = new LoggingAspect();
// 创建代理对象
ILogger proxy = ProxyGenerator.CreateProxy(logger, interceptor);
// 调用代理对象的方法
proxy.Log("Hello, World!");
Console.ReadLine();
}
}
对比一下Java Spring Boot 的AOP
-
动态代理实现方式:在Java Spring Boot中,基于代理的AOP主要使用JDK动态代理和CGLIB代理来实现。而在C#中,使用IL生成器(ILGenerator)直接操作IL指令来生成和修改类型的字节码,实现动态代理。这种方式相对于代理类的生成更加底层,需要对CLR(Common Language Runtime)和IL指令有一定的了解。
-
IL的语法和特性:IL是.NET平台的中间语言,类似于汇编语言,但具有一些.NET特定的语法和特性。IL指令用于描述类型、方法、属性等的结构和操作,需要了解这些指令的使用规则和约束。相比之下,Java字节码(Java bytecode)是Java虚拟机(JVM)上的中间语言,其语法和特性与IL有所不同。
-
第三方库和框架:在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。