有时候为了程序的灵活性,我们都会用到 JAVA 的反射机制,但是它的代价就是性能比较差,特别是高并发的情况下。
我们可以通过动态的修改字节码代替反射,以期获得更高的性能。当然它还可以做更多的事情,例如 Spring 的 AOP 实现就使用该技术。
动态修改字节码的框架很多,这里使用 ASM ,因为它简洁、方便而且高效。
假设一个处理 WEB 请求的 Action ,每个 Action 通过 execute() 方法来处理请求,为了使用方便让一个 Action 处理多个请求,一般有两种实现方式:
一、是使用反射
在 WEB 请求可以增加一个参数,告诉 Action 要执行哪个方法:
String cmd = getActionMethodName(method);
try {
Method m = action.getClass().getMethod(cmd, paras);
Object[] objs = new Object[] { form, module };
return m.invoke(action, objs);
} catch (NoSuchMethodException nsme) {// getMethod
log.error("找不到可执行命令{}", method);
throw new NoSuchMethodException("您访问的页面不存在");
} catch (InvocationTargetException ite) {// invoke
log.error("执行 method 命令出错", ite);
throw new Exception(ite.getCause().getMessage());
} catch(Exception e) {// other exception
log.error("执行 doActionMehtod 方法出错", e);
return null;
}
这种方式实现比较方便,但是每次请求都会用到反射。
二、利用 ASM 动态修改字节码
基本的原理是 Action 中除 execute() 以外的每个方法都生成一个子类,子类继承该 Action 并实现 exeucte() 方法,子类只对父类特定方法的封装。
public class ParentAction implements IAction {
public Page execute(Form f, Module m) throws Exception {
return m.defaultPage();
}
public Page doChildMethod(Form f, Module m) throws Exception {
return m.defaultPage();
}
}
可以动态生成子类:
public class ChildAction extends ParentAction {
public Page execute(Form f, Module m) throws Exception {
return doChildMethod();
}
}
也就是说每个执行 ParentAction 中 doChildMethod() 方法的请求都会执行 ChildAction 的 exeucte() 方法,这就避免使用反射机制。
// 以下只列出核心的代码
public class MethodActionEnhancer implements Opcodes {
public Object getMethodAction(String cls, String method) {
// 新类的全称
String newcls = cls + method;
try {
return Class.forName(newcls).newInstance();
} catch (Exception e) {
log.warn("未找到类[{}],自动生成", newcls);
try {
byte[] b = dump(cls, method, newcls);
return lc.loadClass(newcls, b).newInstance();
} catch (Exception ex) {
log.error("类[" + newcls + "]加载出错", ex);
return null;
}
}
}
private byte[] dump(String cls, String method, String newcls)
throws Exception {
String f = "Lcom/ezerg/jwdt/web/Form;";
String m = "Lcom/ezerg/jwdt/web/Module;";
String p = "Lcom/ezerg/jwdt/web/Page;";
// 父类的名称
cls = cls.replace(".", "/");
// 子类的名称
newcls = newcls.replace(".", "/");
// 构建 ASM 工具类对象
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, newcls, null, cls, null);
cw.visitSource(newcls + ".java", null);
{ // 构造方法,每个类必须
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);// 方法名称
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(7, l0);
mv.visitVarInsn(ALOAD, 0);// 加载 this 对象
mv.visitMethodInsn(INVOKESPECIAL, cls, "<init>", "()V");// 调用父类的 init 方法
mv.visitInsn(RETURN);// 返回
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "L" + newcls + ";", null, l0, l1, 0);// 本地方法变量
mv.visitMaxs(1, 1);// 设置本地堆栈
mv.visitEnd();
}
{ // execute方法,实现子类的相关方法
mv = cw.visitMethod(ACC_PUBLIC, "execute", "(" + f + m + ")" + p, null, new String[] { "java/lang/Exception" });// 方法名称
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(10, l0);
mv.visitVarInsn(ALOAD, 0);// 加载 this 对象
mv.visitVarInsn(ALOAD, 1);// 加载 f 参数
mv.visitVarInsn(ALOAD, 2);// 加载 m 参数
mv.visitMethodInsn(INVOKEVIRTUAL, cls, method, "(" + f + m + ")" + p);// 调用父类的方法
mv.visitInsn(ARETURN); // 返回对象的引用
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "L" + newcls + ";", null, l0, l1, 0);// 本地方法变量
mv.visitLocalVariable("f", f, null, l0, l1, 1);// 本地方法变量
mv.visitLocalVariable("m", m, null, l0, l1, 2);// 本地方法变量
mv.visitMaxs(3, 3);// 设置本地堆栈
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
分享到:
相关推荐
ASM操作字节码,动态生成Java类class文件,模拟Spring的AOP实现原理。
字节码生成库是生成和转换java字节码的高级api。
ASM Java字节码操作框架PPT,结合已有AOP实现方法,对比所有对Java字节码操作方法做比较
使用 ASM 从 Java 字节码生成控制流图 作者 佩纳安东尼 布朗丁·尼古拉斯 巴登·杰里米 要求 已安装 开发商 您必须位于项目文件夹(pom.xml 文件所在的位置)才能使用以下命令进行编译: mvn compile 然后运行项目...
NULL 博文链接:https://name327.iteye.com/blog/1554558
ASM是一个java字节码操纵框架,它能被用来动态...asm字节码增强技术主要是用来反射的时候提升性能的,如果单纯用jdk的反射调用,性能是非常低下的,而使用字节码增强技术后反射调用的时间已经基本可以与直接调用相当了
ASM 帮助文档(java字节码操作) 对字节码进行操作的jar包。
一个简单的通过ASM修改字节码实现AOP功能的实例,简单易懂,可运行...
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...
内容包含ASM4.0中文手册,以及四种ASM常见的字节码操作应用范例,包含最新版本的ASM9.2的jar包,包含asm-9.2.jar,asm-commons-9.2.jar,asm-util-9.2.jar。 学习文章地址 ...
ASM是一个通用的Java字节码操作和...ASM提供与其他Java字节码框架类似的功能,但专注于 性能。因为它的设计和实现尽可能小而且快,所以它非常适合在动态系统中使用(但当然也可以以静态方式使用,例如在编译器中)。
JavaAgent Javassist 与 Asm JavaAgent 字节码动态编程项目
ASM 4 的中文文档 网上的博文都是从这上边摘得,大家下载下来学学就会了,这个是最全的了。我就是通过这个学会的。
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...
jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效...注:asm其实就是java字节码控制.
埋点计时Gradle插件,利用ASM插入字节码,对指定包名内的类或指定注解的方法,打印其方法的耗时时间。
ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...
NULL 博文链接:https://wuaner.iteye.com/blog/1011036
ASM是一套java字节码生成架构,它可以动态生成二进制格式的stub类或其它代理类, 或者在类被java虚拟机装入内存之前,动态修改类。 现在挺多流行的框架都使用到了asm.所以从aop追溯来到了这。
主要给大家介绍了关于java字节码框架ASM如何操作字节码的相关资料,文中通过示例代码介绍的很详细,有需要的朋友可以参考借鉴,下面来一起看看吧。