C# 使用Emit实现动态AOP框架 (三)
目 录
准备工作完成后,DynamicProxy类就可以开始了。
创建代理对象 Create
创建代理对象主要分为五步:
(1)、获取被代理类型构造函数参数列表
Type[] parameterTypes = parameters == null ? Type.EmptyTypes : parameters.Select(p => p.GetType()).ToArray(); (2)、根据构造函数参数列表创建代理类型
Type proxyType = CreateProxyType(srcType, parameterTypes); (3)、使用动态方法生成创建代理类型实例的委托
CreateFunc<T>(proxyType, parameterTypes) (4)、生成ProxyType对象,存入代理类型字典,以备二次调用
obj = new ProxyType<T>(srcType.FullName, signature, CreateFunc<T>(proxyType, parameterTypes)); func_Dictionary.Add(srcType.FullName + "(" + signature + ")", obj); (5)、通过委托生成代理对象
Func<object[], T> func = (obj as ProxyType<T>).CreateFunc; if (func == null)
throw new Exception("unknown exception"); return func(parameters);
/// <summary>
/// 创建代理类型
/// </summary>
/// <param name="srcType">类型</param>
/// <param name="parameterTypes">参数</param>
/// <returns></returns>
private static Type CreateProxyType(Type srcType, Type[] parameterTypes)
{
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); foreach (var propertyInfo in srcType.GetProperties())
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); //切入方法
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); for (int i = ; i < methods.Length; i++)
{
var method = methods[i]; if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
} Type result = bc.DynamicTypeBuilder.CreateType(); bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); return result;
}
1.1、根据构造函数参数列表创建代理类型 CreateProxyType
(1)、通过Emit生成动态程序集、动态模块以及动态类型
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes);
(2)、重写被切入的属性
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo);
(3)、重写被切入的方法
OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
(4)、生成代理类型
Type result = bc.DynamicTypeBuilder.CreateType();
/// <summary>
/// 创建代理类型
/// </summary>
/// <param name="srcType">类型</param>
/// <param name="parameterTypes">参数</param>
/// <returns></returns>
private static Type CreateProxyType(Type srcType, Type[] parameterTypes)
{
XNet.XCore.XDynamic.BuilderCollection bc = new XDynamic.BuilderCollection
(srcType.Name + "_Aop_Assmely", srcType.Name + "_Aop_Module", srcType.Name + "_Proxy", srcType, parameterTypes); foreach (var propertyInfo in srcType.GetProperties())
OverrideProperty(bc.DynamicTypeBuilder, propertyInfo); //切入方法
MethodInfo[] methods = srcType.GetMethods(BindingFlags.Public | BindingFlags.Instance); for (int i = ; i < methods.Length; i++)
{
var method = methods[i]; if (!method.IsPublic || !method.IsVirtual || XDynamic.IsObjectMethod(method)) continue; object[] aspectAttributes = method.GetCustomAttributes(typeof(AspectAttribute), false); OverrideMethod(bc.DynamicTypeBuilder, method, aspectAttributes);
} Type result = bc.DynamicTypeBuilder.CreateType(); bc.DynamicAssemblyBuilder.Save(bc.AssemblyName.Name + ".dll"); return result;
}
1.1.1 重写被切入的属性 OverrideProperty
/// <summary>
/// 重写被代理类的属性
/// </summary>
/// <param name="dynamicTypeBuilder"></param>
/// <param name="info">属性信息</param>
/// <param name="rangeType">切面范围</param>
/// <param name="onEntryExit">切面公共调用方法</param>
private static void OverrideProperty(TypeBuilder dynamicTypeBuilder, PropertyInfo info)
{
//不需要切入直接返回
object[] aspectAttributes = info.GetCustomAttributes(typeof(AspectAttribute), false); if (aspectAttributes.Length == ) return; PropertyBuilder dynamicPropertyBuilder = dynamicTypeBuilder.DefineProperty(info.Name, PropertyAttributes.HasDefault, info.PropertyType, null); //Getter Setter 方法标识
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual; MethodBuilder getter = dynamicTypeBuilder.DefineMethod("get_" + info.Name, getSetAttr, info.PropertyType, Type.EmptyTypes); ILGenerator getIL = getter.GetILGenerator(); ILGenerateProxyMethod(getIL, info.GetGetMethod(), Type.EmptyTypes, aspectAttributes); //覆盖自动生成的Getter
MethodInfo getMethod = info.GetGetMethod(); if (getMethod != null) dynamicTypeBuilder.DefineMethodOverride(getter, getMethod); //给属性设置Get、Set方法
dynamicPropertyBuilder.SetGetMethod(getter); //重写Set 方法
MethodBuilder setter = dynamicTypeBuilder.DefineMethod("set_" + info.Name, getSetAttr, typeof(void), new Type[] { info.PropertyType }); ILGenerator setIL = setter.GetILGenerator(); ILGenerateProxyMethod(setIL, info.GetSetMethod(), new Type[] { info.PropertyType }, aspectAttributes); //覆盖自动生成的Setter
MethodInfo setMethod = info.GetSetMethod(); if (setMethod != null) dynamicTypeBuilder.DefineMethodOverride(setter, setMethod); dynamicPropertyBuilder.SetSetMethod(setter);
}
1.1.2 重写被切入的方法 OverrideMethod
/// <summary>
/// 重写被代理类的指定方法
/// </summary>
/// <param name="typeBuilder">类型</param>
/// <param name="src_Method">被代理方法</param>
/// <param name="aspectAttributes">代理特性集合</param>
private static void OverrideMethod(TypeBuilder typeBuilder, MethodInfo src_Method, object[] aspectAttributes)
{
if (aspectAttributes == null || aspectAttributes.Length == ) return; MethodAttributes attr = MethodAttributes.Public | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.Virtual; //获取当前方法参数列表
Type[] paramTypes = XDynamic.GetMethodParameterTypes(src_Method); ILGenerator il = typeBuilder.DefineMethod(src_Method.Name, attr, src_Method.ReturnType, paramTypes).GetILGenerator(); ILGenerateProxyMethod(il, src_Method, paramTypes, aspectAttributes);
}
1.1.3 生成代理方法 ILGenerateProxyMethod
/// <summary>
///
/// </summary>
/// <param name="il_ProxyMethod"></param>
/// <param name="src_Method"></param>
/// <param name="paramTypes"></param>
/// <param name="aspectAttributes"></param>
private static void ILGenerateProxyMethod(ILGenerator il_ProxyMethod, MethodInfo src_Method, Type[] paramTypes, object[] aspectAttributes)
{
int aspectCount = aspectAttributes.Length; //生成切面上下文
LocalBuilder aspectContext = CreateAspectContext(il_ProxyMethod, src_Method.Name, paramTypes); //申明临时存放切面对象和OnExit方法的变量
var aspectLocalBuilders = new LocalBuilder[aspectCount];
var onExit_Methods = new MethodInfo[aspectCount]; //初始化标记的切面对象,并调用切面对象的OnEntry方法
for (int i = ; i < aspectCount; i++)
{
//创建一个切面对象
var aspectType = aspectAttributes[i].GetType();
var aspect = il_ProxyMethod.DeclareLocal(aspectType);
ConstructorInfo constructor = aspectType.GetConstructor(Type.EmptyTypes); il_ProxyMethod.Emit(OpCodes.Newobj, constructor);
il_ProxyMethod.Emit(OpCodes.Stloc, aspect); var onEntry_method = aspectType.GetMethod("OnEntry");
onExit_Methods[i] = aspectType.GetMethod("OnExit"); //调用BeforeInvoke
il_ProxyMethod.Emit(OpCodes.Ldloc, aspect);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onEntry_method);
il_ProxyMethod.Emit(OpCodes.Nop); aspectLocalBuilders[i] = aspect;
} //类对象,参数值依次入栈
for (int i = ; i <= paramTypes.Length; i++)
il_ProxyMethod.Emit(OpCodes.Ldarg, i); //调用基类的方法
il_ProxyMethod.Emit(OpCodes.Call, src_Method); //定义返回值
LocalBuilder result = null; //如果有返回值,保存返回值到局部变量
if (src_Method.ReturnType != typeof(void))
{
result = il_ProxyMethod.DeclareLocal(src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Stloc, result); //给AspectContext的属性Result赋值
var resultSetMethod = typeof(AspectContext).GetMethod("set_Result");
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext); //加载AspectContext局部变量
il_ProxyMethod.Emit(OpCodes.Ldloc, result);//加载返回值
il_ProxyMethod.Emit(OpCodes.Box, src_Method.ReturnType);
il_ProxyMethod.Emit(OpCodes.Call, resultSetMethod);//赋值
} //调用横切对象的OnExit方法
for (int i = ; i < aspectCount; i++)
{
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectLocalBuilders[i]);
il_ProxyMethod.Emit(OpCodes.Ldloc, aspectContext);
il_ProxyMethod.Emit(OpCodes.Callvirt, onExit_Methods[i]);
il_ProxyMethod.Emit(OpCodes.Nop);
} //如果有返回值,则把返回值压栈
if (result != null)
il_ProxyMethod.Emit(OpCodes.Ldloc, result); il_ProxyMethod.Emit(OpCodes.Ret);//返回
}
1.1.4 生成切面上下文对象 CreateAspectContext
/// <summary>
/// 生成切面上下文对象
/// </summary>
/// <param name="il"></param>
/// <param name="methodName">方法名称</param>
/// <param name="paramTypes">参数类型</param>
/// <returns></returns>
private static LocalBuilder CreateAspectContext(ILGenerator il, string methodName, Type[] paramTypes)
{
//AspectContext.ParameterArgs 类型为 object[] //声明一个类型为object的局部数组
il.DeclareLocal(typeof(object[]));
//数组长度入栈
il.Emit(OpCodes.Ldc_I4, paramTypes.Length);
//生成新数组
il.Emit(OpCodes.Newarr, typeof(object));
//赋值给局部数组变量
il.Emit(OpCodes.Stloc_0); //遍历参数,并存入数组
for (int i = ; i < paramTypes.Length; i++)
{
il.Emit(OpCodes.Ldloc_0);//数组入栈
il.Emit(OpCodes.Ldc_I4, i);//数组下标入栈
il.Emit(OpCodes.Ldarg, i + );//按下标加载对应的参数
if (paramTypes[i].IsValueType)//参数为值类型,装箱
il.Emit(OpCodes.Box, paramTypes[i]);
il.Emit(OpCodes.Stelem_Ref);//将参数存入数组
} //获取AspectContext构造函数
Type aspectContextType = typeof(AspectContext);
ConstructorInfo info = aspectContextType.GetConstructor(new Type[] { typeof(object), typeof(string), typeof(object[]) }); //生成一个AspectContext 对象
il.Emit(OpCodes.Ldarg_0);//加载调用对象
il.Emit(OpCodes.Ldstr, methodName);//加载方法名称
il.Emit(OpCodes.Ldloc_0);//加载由参数生成的局部数组变量
il.Emit(OpCodes.Newobj, info); //声明一个AspectContext局部变量
LocalBuilder aspectContext = il.DeclareLocal(aspectContextType);
il.Emit(OpCodes.Stloc, aspectContext); return aspectContext;
}
1.2 使用动态方法生成创建代理类型实例的委托
/// <summary>
/// 生成创建代理类型实例的委托
/// </summary>
/// <typeparam name="T">被代理类型</typeparam>
/// <param name="proxyType">代理类型</param>
/// <param name="parameterTypes">代理类型构造函数参数类型</param>
/// <returns></returns>
private static Func<object[], T> CreateFunc<T>(Type proxyType, Type[] parameterTypes)
{
DynamicMethod method = new DynamicMethod(proxyType.Name + "_CF", typeof(T), new Type[] { typeof(object[]) }, true); var il = method.GetILGenerator(); //根据T类型的构造函数参数列表,依次将 object[] parameters 中对应的值加载到堆栈(并做相应类型转换),以被T类型的构造函数使用
for (int i = ; i < parameterTypes.Length; i++)
{ il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldelem_Ref); if (parameterTypes[i].IsValueType)
// 如果是值类型,拆箱
il.Emit(OpCodes.Unbox_Any, parameterTypes[i]);
else
// 如果是引用类型,转换
il.Emit(OpCodes.Castclass, parameterTypes[i]);
} ConstructorInfo info = proxyType.GetConstructor(parameterTypes); if (info == null) throw new Exception("代理类不存在,与指定参数列表相对应的构造函数。"); il.Emit(OpCodes.Newobj, info);
il.Emit(OpCodes.Ret); //建立《生成指定类型T的实例》的委托
return method.CreateDelegate(typeof(Func<object[], T>)) as Func<object[], T>;
}
1.3 ProxyType类
public class ProxyType<T>
{
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="name">类型名称</param>
/// <param name="parameterSignature">构造函数参数签名</param>
/// <param name="createFunc">创建被代理类型实例的委托</param>
public ProxyType(string name, string parameterSignature, Func<object[], T> createFunc)
{
Name = name; ParameterSignature = parameterSignature; CreateFunc = createFunc;
}
#endregion #region 属性 /// <summary>
/// 名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 参数类型签名
/// </summary>
public string ParameterSignature { get; set; } /// <summary>
/// 创建被代理类型实例的委托
/// </summary>
public Func<object[], T> CreateFunc { get; set; } #endregion
}
到此为止一个简单的Aop框架就完成了。下一篇会介绍一个下BuilderCollection类
C# 使用Emit实现动态AOP框架 (三)的更多相关文章
- C# 使用Emit实现动态AOP框架 (二)
目 录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...
- C# 使用Emit实现动态AOP框架 (一)
目 录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...
- C# 使用Emit实现动态AOP框架 进阶篇之异常处理
目 录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...
- C# 使用Emit实现动态AOP框架 进阶篇之优化
目 录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...
- .NET 下基于动态代理的 AOP 框架实现揭秘
.NET 下基于动态代理的 AOP 框架实现揭秘 Intro 之前基于 Roslyn 实现了一个简单的条件解析引擎,想了解的可以看这篇文章 https://www.cnblogs.com/weihan ...
- C#利用Emit反射实现AOP,以及平台化框架封装思路
C#利用Emit反射实现AOP,以及平台化框架封装思路 这是前两天扒的一段动态代理AOP代码,用的Emit反射生成子类来实现代理模式,在这里做个小笔记,然后讨论一下AOP框架的实现思路. 首先是主函数 ...
- Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架
类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...
- JAVA基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架
1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...
- Dora.Interception,为.NET Core度身打造的AOP框架:全新的版本
Dora.Interception 1.0(Github地址:可以访问GitHub地址:https://github.com/jiangjinnan/Dora)推出有一段时间了,最近花了点时间将它升级 ...
随机推荐
- java经典算法题50道
原文 JAVA经典算法50题[程序1] 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?1.程序 ...
- spring boot jpa-java.lang.IllegalArgumentException: Not a managed type异常问题解决方法
JPA实体类没有被扫描到,导致这样的情况有以下几种可能: 实体类没有加上@Entity注解 对应解决方法在实体类上加上@Entity即可解决问题 没有按照SpringBoot的约定,默认扫描(appl ...
- vue2.0+vue-dplayer实现hls播放
vue2.0+vue-dplayer实现hls播放 开始 安装依赖 npm install vue-dplayer -S 1,编写组件HelloWorld.vue <template> & ...
- 转载: beta分布介绍
最近在看机器学习方面的资料,作为入门的李航教授所写的<统计机器学习>一书,刚看完第一章我也是基本处于懵了的状态,其中有一道题提到贝叶斯估计,看了下网上的资料都提到了一个叫做 beta分布的 ...
- 十个Python爬虫武器库示例,十个爬虫框架,十种实现爬虫的方法!
一般比价小型的爬虫需求,我是直接使用requests库 + bs4就解决了,再麻烦点就使用selenium解决js的异步 加载问题.相对比较大型的需求才使用框架,主要是便于管理以及扩展等. 1.Scr ...
- c++ STL 最大值最小值
#include <iostream>#include <algorithm>#include <deque> using namespace std; //二元谓 ...
- 读取yml 文件中的参数
第一种方法: yml 文件: spring: main: allow-bean-definition-overriding: true cloud: consul: host: 192.168.1.1 ...
- JAVA NIO学习笔记二 频道和缓冲区
Java NIO 频道 Java NIO渠道类似于流,他们之间具有一些区别的: 您可以读取和写入频道.流通常是单向(读或写). 通道可以异步读取和写入数据. 通道常常是读取或写入缓冲区. 如上所述,您 ...
- BTE增强
转自https://www.cnblogs.com/Garfield/p/5313962.html Enhancement(1)--BTEs 最近一个同事碰到一个FI的增强,要用BTEs实现,我也是第 ...
- JAVA 基础编程练习题43 【程序 43 求奇数个数】
43 [程序 43 求奇数个数] 题目:求 0—7 所能组成的奇数个数. package cskaoyan; public class cskaoyan43 { @org.junit.Test pub ...