right
PROGRAMME
您的位置:首页 > 新闻 > 行业动态 >

点击返回首页

ASM字节码框架学习之动态代理

2018-02-12 信息来源:www.mrmhw.com 编辑:admin 阅读次数:

ASM字节码操纵框架,可以直接以二进制的形式来来修改已经存在的类或者创建新的类。ASM封装了操作字节码的大部分细节,并提供了非常方便的接口来对字节码进行操作。ASM框架是全功能的,使用ASM字节码框架,可以方便地对类增加成员,修改方法,创建新的类等。关于ASM的学习,可以参考:。作为学习ASM框架的第一篇总结,本文的主要内容是使用ASM框架实现一个简单的JDK动态代理和CGLIB代理。

设定代理类和被代理类 被代理类

被代理类非常简单。

public interface CalculatorInterface { int add(int i, int j); int sub(int i, int j); } public class Calculator implements CalculatorInterface { public int add(int i, int j) { return i + j; } public int sub(int i, int j) { return i - j; } }

代理类目标代码原型

CGLIB版本的代理类如下,直接从Calculator继承。如果是JDK版本的,则改为实现CalculatorInterface即可。
这里简化了,对要拦截的方法的个数写死了(m1,m2),实际在生成字节码的时候并没有写死。
这一份代码,就是我要用字节码方式生成的代码。

public class CalculatorProxy extends Calculator { private InvocationHandler handler; private Object target private Method m1; private Method m2; public CalculatorProxy(Object o, InvocationHandler h, Method targetMethod1, Method targetMethod2) { super(); target = o; handler = h; m1 = targetMethod1; m2 = targetMethod2; } @Override public int add(final int i, final int j) { try { return (int)handler.invoke(this, m1, new Object[] {i, j}); } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }

代理工厂

代理工厂类似JDK的Proxy对象,只需要向代理工厂对象提供被代理对象和一个InvocationHandler即可使用CGLIB的方式来生成代理类,如果要使用JDK的方式来生成代理对象,则需要再额外提供一下待实现接口。使用newProxy方法得到代理对象。

public class AopProxy { public AopProxy(Object target, InvocationHandler handler) { ... } public AopProxy(Object target, InvocationHandler handler, Class<?>[] interfaces) { ... } public Object newProxy() throws Exception{ } }

生成代理类 基本指令

使用ASM生成一个类最复杂的地方在于方法体的生成,相当于直接写字节码。生成上文的目标类需要用到如下指令:
这个表格说的指令参数,并不是真正的JVM指令的参数,而是使用ASM框架生成相应字节码时需要传递的参数

指令名称 指令参数说明 指令含义 操作数栈
ILOAD   index: unsigned byte   从局部变量表中加载下标为index的int到操作数栈   无参数出栈,结果入栈  
ALOAD   index: unsigned byte   将栈顶的引用写入到局部变量表中下标为index的引用   无参数出栈,结果入栈  
ASTORE   index: unsigned byte   从局部变量表中加载下标为index的引用到操作数栈   objectRef 引用 出栈  
INVOKESPECIAL   owner: string 类名
name: string 方法名
desc:方法签名
itf:boolean 是否是接口(false)
  调用构造器,私有方法,或显示调用父类的方法,静态绑定   objectRef:实例对象 出栈
arg1:第一个参数 出栈
arg...
有返回的话入栈
 
INVOKEVIRTUAL   owner: string 类名
name: string 方法名
desc:方法签名
itf:boolean 是否是接口(false)
  根据对象类型多态调用,动态绑定   objectRef:实例对象 出栈
arg1:第一个参数 出栈
arg...
有返回的话入栈
 
INVOKEINTERFACE   owner: string 类名
name: string 方法名
desc:方法签名
itf:boolean 是否是接口(true)
  根据对象类型多态调用,动态绑定   objectRef:实例对象 出栈
arg1:第一个参数 出栈
arg...
有返回的话入栈
 
NEW   name: string   构造一个类型为name的对象,分配内存,并完成成员初始化,但是并不调用构造方法   无参数出栈,结果入栈  
PUTFIELD   owner: string 类名
name: string 成员名
desc: string 成员类型描述
  设置一个field值   objectRef 实例对象 出栈
value 成员的值 出栈
 
GETFIELD   owner: string 类名
name: string 成员名
desc: string 成员类型描述
  读取一个field值   objectRef 实例对象 出栈
value 成员的值 入栈
 
ANEWARRAY   type: string 类型名称   新建引用类型为type的数组   count:int 数组长度 出栈
arrayref:数组引用 入栈
 
DUP   无参   复制栈顶的数据   value 栈顶的值 出栈
value 栈顶的值 入栈两次
 
AASTORE   无参   将引用存入数组指定位置   arrayRef 数组引用 出栈
index 下标 出栈
value 引用 出栈
 

上一篇:中国保监会 国家外汇管理局发布关于规范 保险 下一篇:集团动态|华电集团与哈电集团深化战略合作

 关于我们 | 网站地图 | 版权申明 | 隐私保护 | 货到付款 | 招聘信息 | 联系我们 | 广告服务 | 疑难解答 | 帮助中心 

网站备案:粤ICP备091426159号

版权所有:美容门户网 Copyright © 2007-2015 提醒您谨防假冒与抄袭