Aop动态生成代理类时支持带参数构造函数

时间:2022-09-11 09:14:16

一、背景

  在某些情况下,我们需要植入AOP代码的类并没有默认构造函数。那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数。自己折腾了1晚上没搞定,现在搞定了发出来供大家一起学习探讨。

二、梳理功能点

  在已支持通过默认构造函数进行AOP代码植入的情况下(以前发过一篇博文,传送门:大家一起Aop),实现该功能我们需要做的是:

  1.如何通过获取原始类的构造函数参数列表,并使用Emit生成代理类的相应构造函数。

  2.如何创建并保存实例化代理类的委托,加快实例化速度。

三、实现方案

  功能1:

  在原来的生成代理类,代理类中的方法处增加生成构造函数的代码。代码很简单,如下:  

             if (_parameters == null || _parameters.Length == )
{
return typeBuilder;
} var baseConstructor = _originalType.GetConstructor(_parameterTypes);
if (baseConstructor == null)
throw new MissingMethodException("未找到相应参数的构造函数"); const MethodAttributes METHOD_ATTRIBUTES = MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Public;
var constructor = typeBuilder.DefineConstructor(METHOD_ATTRIBUTES, CallingConventions.HasThis, _parameterTypes); var il = constructor.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); for (int i = ; i <= _parameters.Length; i++) //这里要注意下,索引为0的参数是当前对象本身
{
il.Emit(OpCodes.Ldarg, i);
} il.Emit(OpCodes.Call, baseConstructor);
il.Emit(OpCodes.Ret); return typeBuilder;

  其中要注意2点,

  ①定义构造函数的时候需要指定MethodAttributes,平常我们代码编写的公有构造函数就是上面写的4个。

  ②因为我们定义的是构造函数,所以此处必须指定CallingConventions.HasThis。至于为什么去看msdn的解释,不在我们本次讨论范围内。

  

  到这里我们的动态类的构造已经完成了,接下去解决功能2:

  这里只要在原先直接取默认构造函数的地方增加一个判断,获取指定参数的构造函数来构造委托。下面贴代码:

         private DynamicMethod GetConstructorMethod<TReturnType>(Type aopType)
{
var method = _parameters == null || _parameters.Length ==
? new DynamicMethod("", typeof(TReturnType), null)
: new DynamicMethod("", typeof(TReturnType), _parameterTypes); var il = method.GetILGenerator(); BuildConstructorIl(il, aopType); return method;
} private void BuildConstructorIl(ILGenerator il, Type aopType)
{
if (_parameters == null || _parameters.Length == )
{
ConstructorInfo info = aopType.GetConstructor(Type.EmptyTypes);
if (info == null)
return; il.Emit(OpCodes.Newobj, info);
il.Emit(OpCodes.Ret);
}
else
{
ConstructorInfo info = aopType.GetConstructor(_parameterTypes);
if (info == null)
return; var localInstance = il.DeclareLocal(aopType);
for (int i = ; i < _parameterTypes.Length; i++) //这里与上面的标红不同,这里因为是直接定义了一个方法,并且不存在实例,所以此处参数从索引0开始
il.Emit(OpCodes.Ldarg, i); il.Emit(OpCodes.Newobj, info); il.Emit(OpCodes.Stloc, localInstance);
il.Emit(OpCodes.Ldloc, localInstance);
il.Emit(OpCodes.Ret);
}
}

  这里需要的注意的点已经标红出来了。但这里仅是核心代码,在外层再封装几个重载用于生成不同的Func<>。

         public Func<TReturnType> CreateFunc<TReturnType>(Type aopType)
{
var method = GetConstructorMethod<TReturnType>(aopType); return method.CreateDelegate(typeof(Func<TReturnType>)) as Func<TReturnType>;
} public Func<TP1, TReturnType> CreateFunc<TP1, TReturnType>(Type aopType)
{
var method = GetConstructorMethod<TReturnType>(aopType); return method.CreateDelegate(typeof(Func<TP1, TReturnType>)) as Func<TP1, TReturnType>;
} public Func<TP1, TP2, TReturnType> CreateFunc<TP1, TP2, TReturnType>(Type aopType)
{
var method = GetConstructorMethod<TReturnType>(aopType); return method.CreateDelegate(typeof(Func<TP1, TP2, TReturnType>)) as Func<TP1, TP2, TReturnType>;
}

大功告成~,再进行一些简单的重构。测试效果:

Aop动态生成代理类时支持带参数构造函数

四、收尾

  源码附上:源码+Demo在此!

  觉得有用记得点赞哦~

作者:  Zachary
出处:https://zacharyfan.com/archives/89.html

▶关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描右侧的二维码~。

定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。

如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。

如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。

Aop动态生成代理类时支持带参数构造函数的更多相关文章

  1. Emit动态生成代理类用于监控对象的字段修改

    利用Emit动态生成代理对象监控对象哪些字段被修改,被修改为什么值 被Register的对象要监控的值必须是Virtual虚类型 必须使用CreateInstance创建对象 必须使用DynamicP ...

  2. svcutil 生成代理类时的问题

    如果有这个的xsd, group内嵌choice的结构: <xs:complexType name="CreateType">        <xs:sequen ...

  3. Java设计模式---(动态)代理模式

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白 ...

  4. java 动态生成SQL

    代码如下: /** * 动态生成SQ及SQL参数L * @param ve 接收到的消息的CHGLIST * @param paramList MQ消息中的SQL参数 * @param t 泛型对象 ...

  5. Java基础---Java---基础加强---类加载器、委托机制、AOP、 动态代理技术、让动态生成的类成为目标类的代理、实现Spring可配置的AOP框架

    类加载器 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader 类加载器也是Jav ...

  6. JAVA基础加强(张孝祥)&lowbar;类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架

    1.类加载器 ·简要介绍什么是类加载器,和类加载器的作用 ·Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader ...

  7. 秒懂C&num;通过Emit动态生成代码 C&num;使用Emit构造拦截器动态代理类

    秒懂C#通过Emit动态生成代码   首先需要声明一个程序集名称, 1 // specify a new assembly name 2 var assemblyName = new Assembly ...

  8. Mybaits 源码解析 (十一)----- 设计模式精妙使用:静态代理和动态代理结合使用:&commat;MapperScan将Mapper接口生成代理注入到Spring

    上一篇文章我们讲了SqlSessionFactoryBean,通过这个FactoryBean创建SqlSessionFactory并注册进Spring容器,这篇文章我们就讲剩下的部分,通过Mapper ...

  9. JDK动态代理&lbrack;4&rsqb;----ProxyGenerator生成代理类的字节码文件解析

    通过前面几篇的分析,我们知道代理类是通过Proxy类的ProxyClassFactory工厂生成的,这个工厂类会去调用ProxyGenerator类的generateProxyClass()方法来生成 ...

随机推荐

  1. Convert BSpline Curve to Arc Spline in OpenCASCADE

    Convert BSpline Curve to Arc Spline in OpenCASCADE eryar@163.com Abstract. The paper based on OpenCA ...

  2. IOS第二天多线程-05NSOperationQueue 暂停,和恢复队列任务

    *********** #import "HMViewController.h" @interface HMViewController () <UITableViewDel ...

  3. Android中ListView放入PopupWindow产生问题解决

    今天在做项目时候发现将ListView放入PopupWindow产生问题,ListView放入PopupWindow后 对PopupWindow设置了setFocusable(true)这时候其他的控 ...

  4. chrome 41 空格 &amp&semi;nbsp&semi;

    chrome 41对半角空格的解析 当做一个汉字宽度来处理了. 导致很多网站出现异常. 目前能想到的方法是删掉用来规范格式的空格. 老版chrome chrome41 和讯网也有这种问题 有更好的处理 ...

  5. H2O与Java线程同步

    Java 5以前的线程同步采用syncronized和wait,notify,notifyAll来实现,比较粗糙.之后有了Lock和Condition.ReentrantLock的简单lock,unl ...

  6. 【JavaScript】history&period;back&lpar;&rpar; 网页已过期

    使用history.back()进行返回时,有时会提示“网页已过期”, 多数是因为目标页面的form为post提交方式,而且是表单已经提交后的响应页面,无法找到form中的具体参数,而“报错”. 具体 ...

  7. Android中build&&num;160&semi;target,minSdkVersion,targetSdkVersion,maxSdkVersion概念区分

    问题引入:   有一个下载功能,在Android 5.x设备上运行正常,Android 6.x上运行异常,现象是下载进度卡在0%.   问题排查发现,是sdk的target设置为23导致,修改为21则 ...

  8. javascript实现小鸟飞行轨迹

    javascript实现小鸟飞行轨迹 代码如下:

  9. red&lpar;&rpar;、redinle&lpar;&rpar;、redlines&lpar;&rpar;三者之间的关系

    # 关于read()方法: # 1.读取整个文件,将文件内容放到一个字符串变量中 # 2.如果文件大于可用内存,不可能使用这种处理 file_object = open("a.txt&quo ...

  10. mysql 主键与外键

    一.主键详解,引用自:https://blog.csdn.net/haiross/article/details/50456154 1.要设置主键自增的话字段必须是整形数字. 二.外键详解:引用自ht ...