一、背景

  在某些情况下,我们需要植入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>;
}

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

四、收尾

  源码附上:源码+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基础加强(张孝祥)_类加载器、分析代理类的作用与原理及AOP概念、分析JVM动态生成的类、实现类似Spring的可配置的AOP框架

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

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

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

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

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

  9. JDK动态代理[4]----ProxyGenerator生成代理类的字节码文件解析

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

随机推荐

  1. Windows2012R2备用域控搭建

    Windows2012R2备用域控搭建 前置操作 域控主域控的主dns:自己的ip,备dns:备域控的ip备域控的主dns:自己的ip,备dns:主域控的ip 客户端主dns:主域控的ip,备dns: ...

  2. jQuery学习之路(3)- 事件

    ▓▓▓▓▓▓ 大致介绍 jQuery增加了并扩展了基本的事件处理机制,不但提供了更加优雅的事件处理语法,而且极大地增强了事件处理能力 ▓▓▓▓▓▓ jQuery中的事件 ▓▓▓▓▓▓ 加载DOM 在j ...

  3. 微信小程序(微信应用号)组件讲解

    这篇文章主要讲解微信小程序的组件. 首先,讲解新建项目.现在有句话:招聘三天以上微信小程序开发,这个估计只能去挖微信的工程师了.技术新,既然讲解,那我们就从开始建项目讲解. 打开微信web开发者工具, ...

  4. C++ 事件驱动型银行排队模拟

    最近重拾之前半途而废的C++,恰好看到了<C++ 实现银行排队服务模拟>,但是没有实验楼的会员,看不到具体的实现,正好用来作为练习. 模拟的是银行的排队叫号系统,所有顾客以先来后到的顺序在 ...

  5. [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法

    一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...

  6. PAT练习题目录

    点题号就能查看题解了,另外代码也放在了开源中国码云上: 甲级:代码集合:https://git.oschina.net/firstmiki/PAT-Advanced-Level-Practise 10 ...

  7. 【centos7常用技巧】RPM打包

    一.RPM打包的目的 1.当目标机中不存在编译环境时,可以先在本地环境中编译打包,然后直接在目标机中用rpm -ivh *.rpm安装即可. 2.当需要在目标机中安装多个软件或者增加多个文件时,可以将 ...

  8. listview下拉刷新和上拉加载更多的多种实现方案

    listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明. 方案一:添加头布局和脚布局        android系统为listview提供了addfootview ...

  9. Oracle Standard Error 列表

    今天,我特意从网上找了一些,以及自己平时总结的,关于错误编号和说明,平时我们在写项目的时候,往往是可能会出现下面这些错误,例如:违反唯一约束,无效的会话ID,等等.希望对大家有点帮助!可以看看,如果有 ...

  10. Unity插件之plyGame教程:DiaQ对话系统

    本文为孤月蓝风编写,转载请注明出处:http://fengyu.name/?cat=game&id=296 DiaQ是plyGame旗下的一款对话及任务系统.拥有可视化的对话及任务编辑器,能够 ...