一、背景

  在某些情况下,我们需要植入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. 【社工】NodeJS 应用仓库钓鱼

    前言 城堡总是从内部攻破的.再强大的系统,也得通过人来控制.如果将入侵直接从人这个环节发起,那么再坚固的防线,也都成为摆设. 下面分享一个例子,利用应用仓库,渗透到开发人员的系统中. 应用仓库 应用仓 ...

  2. ADO.NET对象的详解

    1. Connection 类 和数据库交互,必须连接它.连接帮助指明数据库服务器.数据库名字.用户名.密码,和连接数据库所需要的其它参数.Connection对象会被Command对象使用,这样就能 ...

  3. .Net Core MVC 网站开发(Ninesky) 2.2、栏目管理功能-System区域添加

    在asp或asp.net中为了方便网站的结构清晰,通常把具有类似功能的页面放到一个文件夹中,用户管理功能都放在Admin文件夹下,用户功能都放在Member文件夹下,在MVC中,通常使用区域(Area ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(74)-微信公众平台开发-自定义菜单

    系列目录 引言 1.如果不借用Senparc.Weixin SDK自定义菜单,编码起来,工作量是非常之大 2.但是借助SDK似乎一切都是简单得不要不要的 3.自定义菜单无需要建立数据库表 4.自定义菜 ...

  5. Hive安装配置指北(含Hive Metastore详解)

    个人主页: http://www.linbingdong.com 本文介绍Hive安装配置的整个过程,包括MySQL.Hive及Metastore的安装配置,并分析了Metastore三种配置方式的区 ...

  6. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  7. 【python之路4】循环语句之while

    1.while 循环语句 #!/usr/bin/env python # -*- coding:utf-8 -*- import time bol = True while bol: print '1 ...

  8. 如何让我们的PHP在Jexus中跑起来

    最近一段时间,经常看到不少的朋友在问,应该怎么设置才能够让Jexus支持PHP.其实,Jexus在很早之前就已经是可以支持PHP,像Apache或Nginx一样充当PHP的Web服务器的.不过由于没有 ...

  9. Python 黑帽编程大纲(变化中)

    Python 黑帽编程大纲(预览版) 教程说明: 本系列教程,采用的大纲母本为<Understanding Network Hacks Attack and Defense with Pytho ...

  10. ABP框架 - 时间

    文档目录 本节内容: 简介 时钟 客户端 时区 客户端 绑定器与转换器 简介 虽然有些应用目标市场只是在一个时区,有些应用目标市场是许多不同时区,为满足这种需求并集中化日期操作,ABP为日期操作提供公 ...