`
冲杯茶喝
  • 浏览: 29403 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JAVA字节码文件操作技巧

阅读更多

你知道如何操作JAVA字节码文件吗,这里将介绍与操作Java字节码有关的基本知识和操作Java字节码的方法及Demo,首先我们来看一下AOP的概念,AOP是OOP的延续,是AspectOrientedProgramming的缩写,意思是面向方面编程。

如何操作JAVA字节码文件

本文将介绍与操作Java字节码有关的基本知识和操作Java字节码的方法及Demo,谈到操作Java字节码,不能不谈到AOP(AspectOrientedProgramming),下面来简单介绍一下:

AOP简介

AOP是OOP的延续,是AspectOrientedProgramming的缩写,意思是面向方面编程。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

AOP的一个典型应用就是J2EE。J2EE应用系统只有部署在J2EE容器中才能运行,那么为什么划分为J2EE容器和J2EE应用系统?通过对J2EE容器运行机制的分析,可以发现:实际上J2EE容器分离了一般应用系统的一些通用功能,例如事务机制、安全机制以及对象池或线程池等性能优化机制。

这些功能机制是每个应用系统几乎都需要的,因此可以从具体应用系统中分离出来,形成一个通用的框架平台,而且,这些功能机制的设计开发有一定难度,同时运行的稳定性和快速性都非常重要,必须经过长时间调试和运行经验积累而成,因此,形成了专门的J2EE容器服务器产品,如TomcatJBoss。

简单了解AOP后,再来了解一下AOP底层技术:

AOP(AspectOrientedProgramming)底层技术比较

AOP底层技术比较

从上面的图表中分析可以看到,对于一般的操作Java字节码要求(实际上是能够满足笔者100%的要求),综合考虑功能,性能,可用性,易用性,使用Java字节码框架来操作Java字节码是最佳的选择。

下面来了解一下都有哪些开源操作JavaJava字节码的框架:

Javassist;

cglib;

SERP;

Packagegnu.bytecode;

Cojen;

Jdec;

BCEL;

ObjectWebASM;

JClassLib;

TroveClassFileAPI;

Jiapi;

ClassfileReader&Writer;

JBET;

Retroweaver;

Jen;

Soot

这里重点介绍一下ASM,因为下面将使用ASM框架进行Java字节码修改。

ASM这个Java字节码操控框架能被用来动态生成类或者增强既有类的功能。ASM可以直接产生二进制class文件,也可以在类被加载入Java虚拟机之前动态改变类行为。Javaclass被存储在严格格式定义的.class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及Java字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。下图对当前接触常用的操作Java字节码框架进行了一个比较:

操作Java字节码框架比较 

ASM的几个特性:

1.JAVABased.

ASM是基于JAVA的,即用JAVA实现的。

2.Visitor模式.

对于ASM来说,Javaclass被描述为一棵树;使用“Visitor”模式遍历整个二进制结构。

3.复杂性低.易学易用.

ASM提供了更为现代的编程模型,降低了操作Java字节码的复杂性,使用事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解Java类文件格式的所有细节:ASM框架提供了默认的“responsetaker”处理这一切。

4.较高的性能

对Java字节码进行操作的同时尽量减小的性能的损失(性能的损失是不可避免)。

这里来介绍一下ASM组成及顺序图:

ASM组成及顺序图


Corepackage提供了一个读写、修改Javabytecode的API,并且为其它的package定义了依据。这个package对于生成Javabytecode、实现大多数的bytecode变换而言意义重大。

Treepackage提供了Javabytecode的内存表示法。

Analysispackage提供了基本的数据流分析和类型检查算法,它们将用于在treeoackage中存储Java方法bytecode。

Commonspackage(包含在ASM2.0中)提供了一些常用的bytecode转换和用于简化bytecode生成的适配器。

Utilpackage包含了一些帮助类和简单的bytecode验证器,它们将有助于开发或者测试。

XMLpackage提供了一个用于在bytecode和XML之间进行转换的适配器,和一些允许使用XSLT定义bytecode转换的兼容SAX的适配器。

顺序图:

ASM顺序图 

Demo

这里我们来实现这样一个功能:在不能改变原代码功能的前提下,对于一个特定类的特定方法有没有被测试过,以HelloTaobao类中方法helloHeyun为例。

类HelloTaobao:

  1. publicclassHelloTaobao  
  2. {  
  3. publicvoidhelloHeyun()  
  4. {  
  5. System.out.println(“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”);  
  6. }  
  7. }  
  8.  

主方法类:

  1. publicclassMain  
  2. {  
  3. publicstaticvoidmain(String[]args)  
  4. {  
  5. HelloTaobaoht=newHelloTaobao();  
  6. ht.heyunHeyun();  
  7. }  
  8. }  
  9.  

到这里,我们运行一下程序,会在Console输出字符串:“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”。

下面我们来操作一下Java字节码文件HelloTaobao.class:

1.想操作Java字节码的某一方法,需要继承ASM中的ClassAdapter和MethodAdapter

2.定义类Generator来读入Java字节码文件HellTaobao,改造Java字节码文件,生成改造后的同名Java字节码文件HellTaobao,代码如下:

  1. publicclassGenerator  
  2. {  
  3. publicstaticvoidmain(String[]args)throwsException  
  4. {  
  5. ClassReadercr=newClassReader(“HellTaobao”);  
  6.  
  7. ClassWritercw=newClassWriter(ClassWriter.COMPUTE_MAXS);  
  8.  
  9. ClassAdapterclassAdapter=newByteCodeClassHandler(cw);  
  10.  
  11. cr.accept(classAdapter,ClassReader.SKIP_DEBUG);  
  12.  
  13. byte[]data=cw.toByteArray();  
  14.  
  15. Filefile=newFile(“HellTaobao.class”);  
  16.  
  17. FileOutputStreamfout=newFileOutputStream(file);  
  18.  
  19. fout.write(data);  
  20.  
  21. fout.close();  
  22. }  
  23. }  
  24.  

3.ByteCodeClassHandler(自定义)类继承ClassAdapter(fromASM)

4.ByteCodeClassHandler类中重写visitMethod,这个方法里去判断如果Java字节码文件HelloTaobao.class包含方法helloHeyun就调用ByteCodeMethodHandler类

  1. publicclassByteCodeClassHandlerextendsClassAdapter  
  2. {  
  3. publicByteCodeClassHandler(ClassVisitorcv)  
  4. {  
  5. super(cv);  
  6. }  
  7. publicvoidvisit(intversion,intaccess,Stringname,Stringsignature,  
  8. StringsuperName,String[]interfaces)  
  9. {  
  10. super.visit(version,access,name,signature,superName,interfaces);  
  11. }  
  12. publicvoidvisitSource(Stringsource,Stringdebug)  
  13. {  
  14. super.visitSource(source,debug);  
  15.  
  16. }  
  17. publicvoidvisitEnd()  
  18. {  
  19. }  
  20.  
  21. @Override  
  22.  
  23. publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,  
  24.  
  25. Stringsignature,String[]exceptions)  
  26. {  
  27. MethodVisitormv=cv.visitMethod(access,name,desc,signature,  
  28.  
  29. exceptions);  
  30.  
  31. MethodVisitorwrappedMv=mv;  
  32.  
  33. if(mv!=null)  
  34.  
  35. {  
  36.  
  37. //对于”helloHeyun”方法进行改造  
  38.  
  39. if(name.equals(“helloHeyun”))  
  40. {  
  41.  
  42. //使用自定义MethodVisitor,改写方法内容  
  43.  
  44. wrappedMv=newByteCodeMethodHandler(mv);  
  45. }  
  46. }  
  47. returnwrappedMv;  
  48. }  
  49. }  
  50.  

5.ByteCodeMethodHandler(自定义)继承MethodAdapter(fromASM),这里来做改造想要调用的自定义方法,这里将调用类ControlByteCode(自定义)中的controlByteCodeByHeyun(自定义)方法

  1. publicclassByteCodeMethodHandlerextendsMethodAdapter  
  2. {  
  3. publicByteCodeMethodHandler(MethodVisitormv)  
  4. {  
  5. super(mv);  
  6. }  
  7. publicvoidvisitCode()  
  8. {  
  9. visitMethodInsn(Opcodes.INVOKESTATIC,“ControlByteCode”,  
  10.  
  11. “controlByteCodeByHeyun”,“()V”);  
  12. }  
  13. }  
  14.  

6.ControlByteCode类的controlByteCodeByHeyun方法如下

  1. publicclassControlByteCode  
  2. {  
  3. publicstaticvoidcontrolByteCodeByHeyun()  
  4. {  
  5. System.out.println(“Thismethodhasalreadybeencovered.”);  
  6.  
  7. //TODOrealsecuritycheck  
  8. }  
  9. }  

7.这样,当运行完Generator类中main方法后,会生成一个和原Java字节码文件同名的文件(可以观察出,会比以前的文件大,当然也可以用MD5来确定是两个不同文件)。

8.此时在运行主方法类Main,会发现在Console打印如下:

  1. Hello,ThisisHeyun’sinvestigationaboutcodecoverage!  
  2.  
  3. Thismethodhasalreadybeencovered.  

9.由此,可以看出,在原功能没有变化的前提下,通过改变Java字节码文件,我们实现了CodeCoverage的雏形。实际上,很多CodeCoverage工具(如Cobertura)都是运用此方法来实现Instrument(插装)的。

 

最后交代下那些框架应用了ASM:

CGLIB and ASM

 

FROM:http://developer.51cto.com/art/201009/227243_2.htm

分享到:
评论

相关推荐

    深入理解java类加载机制

    我们将详细讲解字节码文件的结构、语法和格式,以及字节码指令的定义和应用,并通过大量实例进行编程详解,帮助开发人员深入了解Java字节码的使用方法和技巧。 在类加载方面,我们将深入探讨Java程序的类加载原理和...

    java源码包---java 源码 大量 实例

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java源码包4

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java源码包3

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java源码包2

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java...

    Krakatau:Java反编译器,汇编器和反汇编器

    Krakatau为Java字节码提供了一个汇编程序和反汇编程序,它使您可以将二进制类文件转换为人类可读的文本格式,进行更改,然后将其转换回类文件,即使对于混淆的代码也是如此。 您还可以通过手动编写字节码从头开始...

    java jdk实列宝典 光盘源代码

    多种方式读文件内容, 按字节读取文件内容、按字符读取文件内容、按行读取文件内容、随机读取文件内容; 多种方式写文件内容, 按字节写文件内容、按字符写文件内容、按行写文件内容 ; 添加内容到文件结尾;文件的...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java...

    Java虚拟机

    第三部分分析了虚拟机的执行子系统,包括类文件结构、虚拟机类加载机制、虚拟机字节码执行引擎。第四部分讲解了程序的编译与代码的优化,阐述了泛型、自动装箱拆箱、条件编译等语法糖的原理;讲解了虚拟机的热点探测...

    Java之IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输...

    powermock源码学习 支持模拟静态方法、构造函数、final类和方法、私有方法以及移除静态初始化器的模拟工具

    PowerMock的核心功能在于其能够通过提供定制的类加载器和应用一些字节码操作技巧,实现对静态方法、构造方法、私有方法和final方法的模拟。例如,在进行单元测试时,有时候我们并不希望测试数据进入实际的数据库,...

    21天学通Java-由浅入深

    33分钟) 21 1.1 Java的平台简介 21 1.2 安装工具包 22 1.2.1 下载JDK 22 1.2.2 安装JDK 24 1.2.3 查看与设置环境变量 25 1.2.4 JDK常用命令 27 1.2.5 Java各个目录含义 28 1.2.6 要善于使用JDK的帮助文件 ...

    java8看不到源码-awesome-articles:不同主题的文章精选列表

    字节码操作 - 使用 ByteBuddy 在运行时生成代码 一般的 - 处理中断异常 蔚来 - 使用 NIO Socker Selector 而不是一个线程每个连接的方法 - 优秀的视频系列,从每个连接的简单线程到完整的 NIO 服务器,通过对

    深入JVM内核 - 原理、诊断与优化

    课程简介: 目前,Java是最为流行的编程语言之一,它的基础平台就是JVM。除了Java,如JRuby、Scala、Clojure等语言也运行在JVM平台。...介绍JVM的字节码以及反汇编方法,同时介绍JIT相关的参数和应用。

    网管教程 从入门到精通软件篇.txt

    JAR:Java档案文件(一种用于applet和相关文件的压缩文件) JAVA:Java源文件 JAR:Java档案文件(一种用于applet和相关文件的压缩文件) JAVA:Java源文件 JFF,JFIF,JIF:JPEG文件 JPE,JPEG,JPG:JPEG图形...

Global site tag (gtag.js) - Google Analytics