ASM学习,引用自http://qa.taobao.com/?p=6266
<script type="text/javascript"></script>?<script type="text/javascript"></script>
l? Core package提供了一个读写、修改Java bytecode的API,并且为其它的package定义了依据。这个package对于生成Java bytecode、实现大多数的bytecode变换而言意义重大。
l? Tree package提供了Java bytecode的内存表示法。
l? Analysis package提供了基本的数据流分析和类型检查算法,它们将用于在tree oackage中存储Java方法bytecode。
l? Commons package(包含在ASM2.0中)提供了一些常用的bytecode转换和用于简化bytecode生成的适配器。
l? Util package包含了一些帮助类和简单的bytecode验证器,它们将有助于开发或者测试。
l? XML package提供了一个用于在bytecode和XML之间进行转换的适配器,和一些允许使用XSLT定义bytecode转换的兼容SAX的适配器。
顺序图:
?
Demo
这里我们来实现这样一个功能:在不能改变原代码功能的前提下,对于一个特定类的特定方法有没有被测试过,以HelloTaobao类中方法helloHeyun为例。
类HelloTaobao:
public class HelloTaobao
{
??? public void helloHeyun()
??? {??
??? System.out.println(“Hello, This is Heyun’s investigation about code coverage!”);??
??? }
}
主方法类:
public class Main
{
??? public static void main(String[] args)
??? {
?????? HelloTaobao ht = new HelloTaobao();
?????? ht.heyunHeyun();
??? }
}
到这里,我们运行一下程序,会在Console输出字符串:“Hello, This is Heyun’s investigation about code coverage!”
下面我们来操作一下字节码文件HelloTaobao.class:
1. 想操作字节码的某一方法,需要继承ASM中的ClassAdapter和MethodAdapter
2. 定义类Generator来读入字节码文件HellTaobao,改造字节码文件,生成改造后的同名字节码文件HellTaobao,代码如下:
public class Generator
{
??? public static void main(String[] args) throws Exception
??? {
?????? ClassReader cr = new ClassReader(“HellTaobao”);
?????? ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
?????? ClassAdapter classAdapter = new ByteCodeClassHandler(cw);
?????? cr.accept(classAdapter, ClassReader.SKIP_DEBUG);
?????? byte[] data = cw.toByteArray();
?????? File file = new File(“HellTaobao.class”);
?????? FileOutputStream fout = new FileOutputStream(file);
?????? fout.write(data);
?????? fout.close();
??? }
}
3. ByteCodeClassHandler(自定义)类继承ClassAdapter(from ASM)
4. ByteCodeClassHandler类中重写visitMethod,这个方法里去判断如果字节码文件HelloTaobao.class包含方法helloHeyun就调用ByteCodeMethodHandler类
public class ByteCodeClassHandler extends ClassAdapter
{
??? public ByteCodeClassHandler(ClassVisitor cv)
??? {
?????? super(cv);
??? }
??? public void visit(int version, int access, String name, String signature,
?????????? String superName, String[] interfaces)
??? {
?????? super.visit(version, access, name, signature, superName, interfaces);
??? }
??? public void visitSource(String source, String debug)
??? {
?????? super.visitSource(source, debug);
??? }
??? public void visitEnd()
??? {?????
??? }
??? @Override?
??? public MethodVisitor visitMethod(int access, String name, String desc,
?????????? String signature, String[] exceptions)
??? {
?????? MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
????????????? exceptions);
?????? MethodVisitor wrappedMv = mv;
?????? if (mv != null)
?????? {
?????????? // 对于 ” helloHeyun” 方法进行改造
?????????? if (name.equals(“helloHeyun”))
?????????? {
????????????? // 使用自定义 MethodVisitor,改写方法内容
????????????? wrappedMv = new ByteCodeMethodHandler(mv);
?????????? }
?????? }
?????? return wrappedMv;
??? }
}
5. ByteCodeMethodHandler(自定义) 继承 MethodAdapter(from ASM),这里来做改造想要调用的自定义方法,这里将调用类ControlByteCode(自定义)中的controlByteCodeByHeyun(自定义)方法
public class ByteCodeMethodHandler extends MethodAdapter
{
??? public ByteCodeMethodHandler(MethodVisitor mv)
??? {
?????? super(mv);
??? }
??? public void visitCode()
??? {
?????? visitMethodInsn(Opcodes.INVOKESTATIC, “ControlByteCode”,
?????????? “controlByteCodeByHeyun”, “()V”);
??? }
}
6. ControlByteCode 类的controlByteCodeByHeyun 方法如下
public class ControlByteCode
{
??? public static void controlByteCodeByHeyun()
??? {??
??? System.out.println(“This method has already been covered.”);??
??????? //TODO real security check??
??? }
}
7. 这样,当运行完Generator类中main方法后,会生成一个和原字节码文件同名的文件(可以观察出,会比以前的文件大,当然也可以用MD5来确定是两个不同文件)。
8. 此时在运行主方法类 Main,会发现在Console打印如下:
Hello, This is Heyun’s investigation about code coverage!
This method has already been covered.
9. 由此,可以看出,在原功能没有变化的前提下,通过改变字节码文件,我们实现了Code Coverage的雏形。实际上,很多Code Coverage工具(如Cobertura)都是运用此方法来实现Instrument(插装)的。
应用
在介绍了AOP,ASM及如何利用ASM操作字节码Demo后,现在来看下一些使用ASM的典型应用:
l? BEA WebLogic Server 9
l? Berkeley DB Java Edition
l? Oracle TopLink
l? EclipseME
l? JRuby
l? Groovy
l? WebSphere sMash
更多可见http://asm.ow2.org/users.html
测试的联想
作为测试人员,有必要掌握这门技术,下面列出了笔者能想到的操作字节码这项技术对于测试的应用:
l? Code Coverage
l? Fault Injection
l? Profiler
参考:
http://asm.ow2.org/doc/tutorial-asm-2.0.html
http://java-source.net/open-source/bytecode-libraries
VN:F [1.9.7_1111]<!-- comments-header --> <!-- Feedsky FEED 订阅统计发布代码结束 -->-- 订阅我吧! --订阅到 抓虾订阅到 鲜果订阅到 Google订阅到 有道订阅到 netvibes订阅到 Rojo订阅到 Yahoo!订阅到 帮看网订阅到QQ邮箱使用手机阅读IM提醒
功能点算法及在软件测试中的应用Part2
手持设备测试的探索推荐栏目:
论坛——淘测试
黑灯舞会
3T交流会-百家讲坛
淘测试电子期刊问卷调查 
<noscript></noscript>