一、背景

  在某些情况下,我们需要植入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. SQL Server 无法连接到服务器。SQL Server 复制需要有实际的服务器名称才能连接到服务器。请指定实际的服务器名称。

    异常处理汇总-数据库系列  http://www.cnblogs.com/dunitian/p/4522990.html SQL性能优化汇总篇:http://www.cnblogs.com/dunit ...

  2. Word/Excel 在线预览

    前言 近日项目中做到一个功能,需要上传附件后能够在线预览.之前也没做过这类似的,于是乎就查找了相关资料,.net实现Office文件预览大概有这几种方式: ① 使用Microsoft的Office组件 ...

  3. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  4. JS继承之原型继承

     许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在ECMAScript中无法实现接口继承.ECMAScript只支 ...

  5. 消息队列性能对比——ActiveMQ、RabbitMQ与ZeroMQ(译文)

    Dissecting Message Queues 概述: 我花了一些时间解剖各种库执行分布式消息.在这个分析中,我看了几个不同的方面,包括API特性,易于部署和维护,以及性能质量..消息队列已经被分 ...

  6. Flexible 弹性盒子模型之CSS flex-flow

    实例 让弹性盒的元素以相反的顺序显示,且在必要的时候进行拆行: display:flex; flex-flow:row-reverse wrap;   效果预览 浏览器支持 表格中的数字表示支持该属性 ...

  7. Android——eclipse下运行android项目报错 Conversion to Dalvik format failed with error 1解决

    在eclipse中导入android项目,项目正常没有任何错误,但是运行时候会报错,(clean什么的都没用了.....)如图: 百度大神大多说是jdk的问题,解决: 右键项目-Properties如 ...

  8. 简述我的SOA服务治理

    SOA服务治理 1.解决业务部门服务冲突和纠纷2.版本定义与版本管理3.服务备案与服务管理4.业务监督与服务监控 SOA的战略目的 一.业务价值胜过技术策略 二.战略目标胜过具体项目的效益 三.内置的 ...

  9. MyEclipse对Maven的安装

    好记性不如烂笔头,记录一下. 操作系统:windows 7 MyEclipse2015 JDK1.7 maven的下载链接,点这里下载apache-maven-3.0.4-bin.tar.gz. 下载 ...

  10. windows 部署 git 服务器报 Please make sure you have the correct access rights and the repository exists.错误

    这两天在阿里云上弄windows 服务器,顺便部署了一个git服务.根据网上教程一步步操作下来,最后在 remote远程仓库的时候提示 fatal: 'yourpath/test.git' does ...