java字节码操做

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

  如何操做JAVA字节码文件算法

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

  AOP简介设计模式

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

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

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

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

  AOP(AspectOrientedProgramming)底层技术比较app

  从上面的图表中分析能够看到,对于通常的操做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字节码框架进行了一个比较:

 

 

  ASM的几个特性:

 

  1.JAVABased.

 

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

 

  2.Visitor模式.

 

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

 

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

 

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

 

  4.较高的性能

 

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

 

  这里来介绍一下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的适配器。

 

  顺序图:

 

 

***************************************************************************************

 Demo

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

 

  类HelloTaobao:

 

 

  • publicclassHelloTaobao  
  • {  
  • publicvoidhelloHeyun()  
  • {  
  • System.out.println(“Hello,ThisisHeyun’sinvestigationaboutcodecoverage!”);  
  • }  
  • }

 

  主方法类:

 

 

  • publicclassMain  
  • {  
  • publicstaticvoidmain(String[]args)  
  • {  
  • HelloTaobaoht=newHelloTaobao();  
  • ht.heyunHeyun();  
  • }  
  • }  

 

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

 

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

 

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

 

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

 

 

  • publicclassGenerator  
  • {  
  • publicstaticvoidmain(String[]args)throwsException  
  • {  
  • ClassReadercr=newClassReader(“HellTaobao”);  
  •  
  • ClassWritercw=newClassWriter(ClassWriter.COMPUTE_MAXS);  
  •  
  • ClassAdapterclassAdapter=newByteCodeClassHandler(cw);  
  •  
  • cr.accept(classAdapter,ClassReader.SKIP_DEBUG);  
  •  
  • byte[]data=cw.toByteArray();  
  •  
  • Filefile=newFile(“HellTaobao.class”);  
  •  
  • FileOutputStreamfout=newFileOutputStream(file);  
  •  
  • fout.write(data);  
  •  
  • fout.close();  
  • }  
  • }

 

 

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

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

 

  • publicclassByteCodeClassHandlerextendsClassAdapter  
  • {  
  • publicByteCodeClassHandler(ClassVisitorcv)  
  • {  
  • super(cv);  
  • }  
  • publicvoidvisit(intversion,intaccess,Stringname,Stringsignature,  
  • StringsuperName,String[]interfaces)  
  • {  
  • super.visit(version,access,name,signature,superName,interfaces);  
  • }  
  • publicvoidvisitSource(Stringsource,Stringdebug)  
  • {  
  • super.visitSource(source,debug);  
  •  
  • }  
  • publicvoidvisitEnd()  
  • {  
  • }  
  •  
  • @Override  
  •  
  • publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,  
  •  
  • Stringsignature,String[]exceptions)  
  • {  
  • MethodVisitormv=cv.visitMethod(access,name,desc,signature,  
  •  
  • exceptions);  
  •  
  • MethodVisitorwrappedMv=mv;  
  •  
  • if(mv!=null)  
  •  
  • {  
  •  
  • //对于”helloHeyun”方法进行改造  
  •  
  • if(name.equals(“helloHeyun”))  
  • {  
  •  
  • //使用自定义MethodVisitor,改写方法内容  
  •  
  • wrappedMv=newByteCodeMethodHandler(mv);  
  • }  
  • }  
  • returnwrappedMv;  
  • }  
  • }

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

 

  • publicclassByteCodeMethodHandlerextendsMethodAdapter  
  • {  
  • publicByteCodeMethodHandler(MethodVisitormv)  
  • {  
  • super(mv);  
  • }  
  • publicvoidvisitCode()  
  • {  
  • visitMethodInsn(Opcodes.INVOKESTATIC,“ControlByteCode”,  
  •  
  • “controlByteCodeByHeyun”,“()V”);  
  • }  
  • }  

 

 

 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(插装)的。

相关文章
相关标签/搜索