下面我们来操作一下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方法如下
publicclassControlByteCode { publicstaticvoidcontrolByteCodeByHeyun() { System.out.println(“Thismethodhasalreadybeencovered.”); //TODOrealsecuritycheck } }7.这样,当运行完Generator类中main方法后,会生成一个和原Java字节码文件同名的文件(可以观察出,会比以前的文件大,当然也可以用MD5来确定是两个不同文件)。
8.此时在运行主方法类Main,会发现在Console打印如下:
Hello,ThisisHeyun’sinvestigationaboutcodecoverage! Thismethodhasalreadybeencovered.9.由此,可以看出,在原功能没有变化的前提下,通过改变Java字节码文件,我们实现了CodeCoverage的雏形。实际上,很多CodeCoverage工具(如Cobertura)都是运用此方法来实现Instrument(插装)的。
【编辑推荐】