`
lijingyao8206
  • 浏览: 219461 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

ASM系列三 利用Methord组件动态生成方法字节码

阅读更多

 一、概述

      ASMCoreApi 中还提供了对class 中方法的生成和解析的组件。前面两篇着重介绍了ClassVisitor 组件的应用场景。ClassVisitor Api 中的visitMethod(int access, String name, String desc, String signature, String[] exceptions)方法返回了一个MethodVisitor对象,MethodVisitor类提供了对于字节码文件中方法的字节码进行解析。同ClassVisitor一样,MethodVisitor的实例方法也需要按照一定的顺序调用。

visitAnnotationDefault?

( visitAnnotation | visitParameterAnnotation | visitAttribute )*

( visitCode

( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn |

visitLocalVariable | visitLineNumber )*

visitMaxs )?

visitEnd

     对于动态生成方法的实现,ASM 提供的主要接口就是MethodVisitorMethods 组件主要涉及到一下三个类:

     1ClassReader 类负责解析字节码中的method部分,并且顺序调用MethodVisitor的方法。其中MethodVisitor是通过ClassVisitorvisitMethod 返回的对象。而ClassVisitor是通过accept方法的参数形式转递给ClassReaderaccept方法在前面章介绍ASMcore apiClassVisitor部分已经介绍过了。

    2ClassWritervisitMethod方法返回了继承自MethodVisitor的实例。并且以二进制数组的形式构建了编译后的方法。

    3MethodVisitor类似一个事件过滤器,可以接受另一个MethodVisitor实例,代理调用所有这个MethodVisitor实例的方法。这个也是类似于前面两章介绍的ClassVisitor

   下面就开始介绍下用ASM MethodVisitor 如何生成和变更、转移methods字节码。

二、生成字节码methods

 

     在了解ASMmethods api 之前,必须要清楚一些字节码的指令和JVM 执行引擎在运行时数据区是运用字节码指令解释执行的。这里可以参看http://yunshen0909.iteye.com/blog/2220937 以及http://yunshen0909.iteye.com/blog/2221144。这里我们结合《JVM 字节码指令对于栈帧数据操作举例》中的例子。生成如下方法:

 public void addEspresso(int espresso) {    
	   if (espresso > 0) {    
	            this.espresso = espresso;    
	        } else {    
	            throw new IllegalArgumentException();    
	        }    
	    }  

   为了方便查看字节码生成效果,我们通过ClassWriter 来输出字节数组,并写到文件中,方便查看class 文件。对于ClassWriter Api 参考http://yunshen0909.iteye.com/blog/2219540。Java代码如下:

    

package asm.core.asm.core.method;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * methods api 动态生成字节码 Created by yunshen.ljy on 2015/6/24.
 */
public class GenerateClasses {

    public static void main(String[] args) throws IOException {

        ClassWriter cw = new ClassWriter(0);
        cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "bytecode/MethodGenClass", null, "java/lang/Object", null);
        cw.visitField(Opcodes.ACC_PRIVATE, "espresso", "I", null, null).visitEnd();
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "addEspresso", "(I)V", null, null);
        // 方法访问开始
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ILOAD, 1);
        // label 代表跳转的字节码位置。
        Label label = new Label();
        mv.visitJumpInsn(Opcodes.IFLT, label);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ILOAD, 1);
        mv.visitFieldInsn(Opcodes.PUTFIELD, "bytecode/MethodGenClass", "espresso", "I");
        Label end = new Label();
        mv.visitJumpInsn(Opcodes.GOTO, end);
        mv.visitLabel(label);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        // 创建Exception对象指令
        mv.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalArgumentException");
        mv.visitInsn(Opcodes.DUP);
        // 调用方法指令
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V", false);
        mv.visitInsn(Opcodes.ATHROW);
        mv.visitLabel(end);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(2, 2);
        // 方法访问结束
        mv.visitEnd();
        cw.visitEnd();

        byte[] b = cw.toByteArray();

        File file = new File("MethodGenClass.class");
        FileOutputStream fout = new FileOutputStream(file);
        fout.write(b);
        fout.close();
    }

}

 

      这里先说明一下栈图(Stack Map Table)的概念。详见: http://yunshen0909.iteye.com/admin/blogs/2222417

      Java7版本之后,需要强制实现栈图结构,不过还好ASM框架给我们处理了生成字节码栈图的细节。构建栈图在ASM框架中,可以通过在无条件跳转语句后调用mv.visitFrame();方法或者调整ClassWriter() 构造器的参数方式来实现,ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);,构造器中的COMPUTE_FRAMES参数会为我们计算Stack Map Table中的frame。本例中,我们采用“手动挡”。visitFrame(type, nLocal, local, nStack, stack)的第一个参数是stack map frame的操作类型,nLocalnStack是局部变量和操作数栈的sizeLocalstack是包含相关类型的数组。本例中,只有两个frame,且记录的状态中操作数栈都是空的,所以参数是(Opcodes.F_SAME, 0, null, 0, null)

      这里再额外说明一下ClassWriter构造器的另外一种参数。如果我们使用了ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);那么COMPUTE_MAXS 就是替我们计算局部变量表和操作数栈的大小,这时候我们还是需要调用  mv.visitMaxs(2, 2);方法,但是可以传递任意参数,因为COMPUTE_MAXS的方式会帮助我们重新计算局部变量和操作数的size。还需要注意的是COMPUTE_MAXS不会为我们计算StackMapFrame,而COMPUTE_FRAMES既会计算栈size,也会计算StackMapFrame,当然使用COMPUTE_MAXS会让ClassWriter10%,而使用COMPUTE_FRAMES会慢20%(数据来自ASM官方说明文档,这里就不再测试)。当然,我觉得,如果使用起来的话,我还是宁可用自动挡。这样可以适当增强代码可读性,减少了代码维护成本。如果有很好的算法(如果你确定你比ASM框架写出了更好的实现算法)来计算这些参数,当然手动挡也是一种乐趣。

      上述实现中我们看到了Label label = new Label()这个语句中,label的作用是为了条件跳转,其实也可以理解成字节码指令的参数。所以label必须对应一条字节码指令,通过visitLabel(label)来调用,并且visitLabel的调用必须紧跟随着label对象指定的指令。如例子中,第一个label指向goto后,所以顺序必须是:mv.visitJumpInsn(Opcodes.GOTO, end);

        mv.visitLabel(label);,第二个label也是同理。但是多个字节码指令可能指向同一个label,比如同时跳转到某一个指令执行的情况,并且label是方法独有的,label对象不能跨方法调用。

      下面我们再看一下,例中方法生成的字节码信息。

     

   
     后续会继续介绍Method Api 的另外一种用法,其实猜猜也知道,同ClassVisitor一样,不仅可以生成字节码,当然也可以动态改变、添加、删除方法的字节码。

 

  • 大小: 33.4 KB
2
3
分享到:
评论
8 楼 taindy 2015-07-06  
妹子有男票吗
7 楼 lxwt909 2015-06-29  
lijingyao8206 写道
o(╯□╰)o交流编程在博客~~~
lxwt909 写道
lijingyao8206 写道
O(∩_∩)O哈哈~
lxwt909 写道
不容易啊,终于发现个女程序员


妹纸留下你的QQ号可好


除了聊编程还可以聊人生谈理想啊
6 楼 lijingyao8206 2015-06-29  
一点不牛逼,所以才要学~
niunianss 写道
女程序员也可以这么牛逼啊

5 楼 lijingyao8206 2015-06-29  
o(╯□╰)o交流编程在博客~~~
lxwt909 写道
lijingyao8206 写道
O(∩_∩)O哈哈~
lxwt909 写道
不容易啊,终于发现个女程序员


妹纸留下你的QQ号可好

4 楼 niunianss 2015-06-29  
女程序员也可以这么牛逼啊
3 楼 lxwt909 2015-06-28  
lijingyao8206 写道
O(∩_∩)O哈哈~
lxwt909 写道
不容易啊,终于发现个女程序员


妹纸留下你的QQ号可好
2 楼 lijingyao8206 2015-06-28  
O(∩_∩)O哈哈~
lxwt909 写道
不容易啊,终于发现个女程序员

1 楼 lxwt909 2015-06-28  
不容易啊,终于发现个女程序员

相关推荐

    ASM操作字节码,动态生成Java类class文件

    ASM是一个开源的Java字节码操控和分析框架,它能够用来动态生成类或者增强已有类的功能。ASM可以被用来创建Java代理、实现元编程、甚至深入到Java虚拟机(JVM)层面进行性能优化。在Java开发中,ASM库允许我们直接...

    ASM字节码操作简单实例

    ASM字节码库是Java字节码操作的强大工具,它允许程序员在运行时动态生成类或者增强已有类的功能。在本实例中,我们将探讨如何利用ASM实现简单的面向切面编程(AOP)功能,这是一种在不修改源代码的情况下,添加额外...

    cglib,字节码生成库是生成和转换Java字节码的高级API。它被aop、测试、数据访问框架用来生成动态代理对象和拦截字段访问。.zip

    CGlib库利用ASM库(一个底层的Java字节码操作和分析框架)来生成和修改字节码。通过这种方式,开发者可以在程序运行时动态地创建新的类或修改现有类的行为,而无需重新编译源代码。 **动态代理** CGlib常用于实现...

    ASM 字节码修改工具中文帮助手册

    ### ASM 字节码修改工具中文帮助手册知识点概览 #### 1. ASM 4.0 简介 - **版本信息**: ASM 4.0 是一个 Java 字节码操作和分析框架,由 Eric Bruneton 开发并维护,版权归属 Eric Bruneton(2007-2011)。 - **...

    Android-埋点计时Gradle插件利用ASM插入字节码

    它可以直接生成和修改Java类的字节码,从而实现诸如动态代理、代码混淆、性能监控等功能。在这个插件中,ASM被用来在运行时动态插入代码,记录并打印指定类或注解方法的执行时间。 插件的使用流程大致如下: 1. ...

    [字节码系列]ObjectWeb ASM构建Method Monitor

    【字节码系列】ObjectWeb ASM构建Method Monitor 在Java世界中,字节码是运行在JVM(Java虚拟机)上的程序表示形式。它是一种中间语言,允许开发者对Java代码进行低级别的操作,比如性能优化、动态代理、代码混淆等...

    cglibJava字节码生成库

    【标题】:“cglib——Java字节码生成库”是一个强大的工具,用于在运行时动态创建和修改类的字节码。它是一个广泛应用于Java开发中的库,特别是那些需要底层控制对象实例化、方法调用等场景的项目。 【描述】:...

    ASM Java字节码操作框架

    ASM Java字节码操作框架PPT,结合已有AOP实现方法,对比所有对Java字节码操作方法做比较

    Java字节码和asm入门资料

    ASM是一个开源的Java字节码操控和分析框架,它可以直接用来生成和修改Java类文件,是Java动态代理和字节码增强技术的重要工具。在深入学习Java字节码和ASM之前,我们需要先理解Java编译和运行的基本过程。 1. **...

    Android字节码插桩

    ASM提供了一种低级别的API,允许开发者直接操作字节码,因此可以用来创建复杂的类转换器和字节码生成器。在Android开发中,ASM常用于动态代理、AOP(面向切面编程)和插桩技术。 **字节码插桩** 字节码插桩是...

    Java Classloading Mechanism : ClassLoader & ASM & 动态字节码增强

    在本篇中,我们将详细探讨ClassLoader的工作原理、ASM库的使用以及如何利用这些工具进行动态字节码增强。 首先,我们来看Java的类加载机制。Java中的类加载主要由ClassLoader完成,它遵循“双亲委派模型”(Parents...

    字节码实战包含class,字节码.zip

    6. **动态字节码技术**: 动态代理、AOP(面向切面编程)、反射等高级Java特性都依赖于字节码操作。例如,CGLIB、ASM等库可以在运行时生成和修改字节码,实现动态类的创建和功能增强。 7. **JVM内存模型与字节码**...

    Java字节码操纵框架 asm-3.1组件包大集合

    ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class ...

    Android-Android无痕埋点框架使用ASM插桩实现

    总结起来,使用ASM插桩实现的Android无痕埋点框架,是通过动态字节码技术,自动跟踪用户行为并记录数据,减少了手动埋点的工作量,提高了数据收集的准确性和效率。对于大型的Android应用来说,这样的框架是不可或缺...

    演示Asm字节码插桩asmd-demo-master.zip

    Asm字节码插桩是一种在Java字节码层面对程序进行动态修改的技术,它允许开发者在不修改源代码的情况下,向已有的类或方法中插入额外的代码。这种技术在性能监控、日志记录、行为追踪、代码优化等领域有广泛应用。在...

    代码生成工具asm-3.2

    4. **动态语言实现**:一些动态语言的Java实现,如Groovy和Jython,使用ASM来生成Java字节码。 5. **框架开发**:例如Spring AOP和Hibernate ORM等框架,利用ASM进行字节码增强,实现AOP切面和对象关系映射。 **API...

    asm动态生成class,并且动态加载执行

    NULL 博文链接:https://name327.iteye.com/blog/1554558

    JAVA字节码操作库 BCEL

    2. **字节码生成**:BCEL提供了一套接口和类,使得开发者可以动态地生成字节码,这对于创建动态代理、AOP(面向切面编程)等场景非常有用。 3. **代码优化**:通过修改字节码,BCEL可以实现代码的优化,例如去除...

    ASM插桩在Android项目中的应用

    ASM是一个Java字节码操控和分析框架,它允许动态生成类或修改已有的类,尤其适用于运行时代码增强和静态代码插桩。本文将深入探讨ASM如何在Android项目中发挥作用,以及如何通过ASMInjectTest进行实践。 首先,了解...

    Java字节码实现Aop

    总结来说,Java字节码实现AOP是一种高效且灵活的技术手段,通过ASM、CGLIB等字节码工具,可以在运行时动态地修改类的行为,实现面向切面编程。理解并掌握这项技术,对于提升Java开发效率和代码质量具有重要意义。

Global site tag (gtag.js) - Google Analytics