使用javassist动态注入代码
来源:互联网 发布:域名批量注册查询 编辑:程序博客网 时间:2024/05/18 00:13
关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
下面通过一个简单的例子,通过javassist来实现如何动态注入代码。
假设,存在类A,如下:
public class A {
public void method() {
for (int i = 0; i < 1000000; i++) {
}
System.out.println("method1");
}
}
测试类B如下:
public class B {
public static void main(String[] args) {
A a = new A();
a.method();
}
}
现在想统计一下method的执行时间,
默认的实现是修改method:
public void method() {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
}
System.out.println("method1");
long end = System.currentTimeMillis();
System.out.println(end - start);
}
如果A的方法很多,统计方法的执行时间的代码就会相应的增加。为了减少工作量,通过动态注入代码的形式来实现。
修改B的main方法:
public static void main(String[] args) throws Exception {
//用于取得字节码类,必须在当前的classpath中,使用全称
CtClass ctClass = ClassPool.getDefault().get("org.esoft.A");
//需要修改的方法名称
String mname = "method";
CtMethod mold = ctClass.getDeclaredMethod(mname);
//修改原有的方法名称
String nname = mname + "$impl";
mold.setName(nname);
//创建新的方法,复制原来的方法
CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);
//主要的注入代码
StringBuffer body = new StringBuffer();
body.append("{\nlong start = System.currentTimeMillis();\n");
//调用原有代码,类似于method();($$)表示所有的参数
body.append(nname + "($$);\n");
body.append("System.out.println(\"Call to method "
+ mname
+ " took \" +\n (System.currentTimeMillis()-start) + "
+ "\" ms.\");\n");
body.append("}");
//替换新方法
mnew.setBody(body.toString());
//增加新方法
ctClass.addMethod(mnew);
//类已经更改,注意不能使用A a=new A();,因为在同一个classloader中,不允许装载同一个类两次
A a=(A)ctClass.toClass().newInstance();
a.method();
}
这只是简单的一个应用。javassist还提供了很多的功能,用于更改类结构。有兴趣的可以参考相关文档
下面通过一个简单的例子,通过javassist来实现如何动态注入代码。
假设,存在类A,如下:
public class A {
public void method() {
for (int i = 0; i < 1000000; i++) {
}
System.out.println("method1");
}
}
测试类B如下:
public class B {
public static void main(String[] args) {
A a = new A();
a.method();
}
}
现在想统计一下method的执行时间,
默认的实现是修改method:
public void method() {
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
}
System.out.println("method1");
long end = System.currentTimeMillis();
System.out.println(end - start);
}
如果A的方法很多,统计方法的执行时间的代码就会相应的增加。为了减少工作量,通过动态注入代码的形式来实现。
修改B的main方法:
public static void main(String[] args) throws Exception {
//用于取得字节码类,必须在当前的classpath中,使用全称
CtClass ctClass = ClassPool.getDefault().get("org.esoft.A");
//需要修改的方法名称
String mname = "method";
CtMethod mold = ctClass.getDeclaredMethod(mname);
//修改原有的方法名称
String nname = mname + "$impl";
mold.setName(nname);
//创建新的方法,复制原来的方法
CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);
//主要的注入代码
StringBuffer body = new StringBuffer();
body.append("{\nlong start = System.currentTimeMillis();\n");
//调用原有代码,类似于method();($$)表示所有的参数
body.append(nname + "($$);\n");
body.append("System.out.println(\"Call to method "
+ mname
+ " took \" +\n (System.currentTimeMillis()-start) + "
+ "\" ms.\");\n");
body.append("}");
//替换新方法
mnew.setBody(body.toString());
//增加新方法
ctClass.addMethod(mnew);
//类已经更改,注意不能使用A a=new A();,因为在同一个classloader中,不允许装载同一个类两次
A a=(A)ctClass.toClass().newInstance();
a.method();
}
这只是简单的一个应用。javassist还提供了很多的功能,用于更改类结构。有兴趣的可以参考相关文档
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用javassist动态注入代码
- 使用字节码处理框架javassist动态注入代码
- Xcode使用Dyci动态注入代码
- Android热补丁动态修复技术(三)—— 使用Javassist注入字节码,完成热补丁框架雏形(可使用)
- Android热补丁动态修复技术(三)—— 使用Javassist注入字节码,完成热补丁框架雏形(可使用)
- 委托代码动态注入
- 游戏远程代码注入和动态连接库的使用
- 游戏远程代码注入和动态连接库的使用
- 游戏远程代码注入和动态连接库的使用
- TCP三次握手/四次挥手
- Linux 进程间通信——消息队列实现双向通信
- linux socket常用函数
- 判断俩个链表是否相交
- SAP BW问题一览
- 使用javassist动态注入代码
- 爱是一种直觉
- UIView.h
- ubuntu12.04修改开机默认启动项
- Qt坐标绘图
- SQL WITH TIES
- 如何练字
- Qt坐标系统
- Primer plus C++ 第十六章 标准模板库_vector模板类