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

相關文章
相關標籤/搜索