Javassist字节码技术

Java动态编程的作用:

     通过配置生成代码,减少重复编码和维护成本

      我们常用到的动态特性主要是反射,在运行时查找对象属性、方法,修改作用域,通过方法名称调用方法等。在线的应用不会频繁使用反射,因为反射的性能开销较大。其实还有一种和反射一样强大的特性,但是开销却很低,它就是Javassit。

      Javassit其实就是一个二方包,提供了运行时操作Java字节码的方法大家都知道,Java代码编译完会生成.class文件,就是一堆字节码。JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码。


要想将编译时不存在的类在运行时动态创建并加载,通常有两种策略:

1.      动态编译

2.      动态生成二进制字节码(.class)

     对于第二种策略,实际上已经有诸多比较成熟的开源项目提供支持,如CGLib、ASM、Javassist等。这些开源项目通常都具备两方面的功能:

1.      动态创建新类或新接口的二进制字节码

2.      动态扩展现有类或接口的二进制字节码

       其中,CGLib的底层基于ASM实现,是一个高效高性能的生成库;而ASM是一个轻量级的类库,但需要涉及到JVM的操作和指令;相比而言,Javassist要简单的多,完全是基于Java的API,但其性能相比前二者要差一些。

尽管如此,在性能要求相对低的场合,Javassist仍然十分有用,如JBoss中就调用了Javassist。


如下的代码是动态创建Java类二进制字节码并通过反射调用的示例,可供参考:

[java]  view plain  copy
  1. package com.test.TestForDubbo;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import javassist.CannotCompileException;    
  6. import javassist.ClassPool;    
  7. import javassist.CtClass;    
  8. import javassist.CtConstructor;    
  9. import javassist.CtField;    
  10. import javassist.CtNewMethod;    
  11. import javassist.Modifier;    
  12. import javassist.NotFoundException;    
  13. import javassist.CtField.Initializer;    
  14.   
  15.   
  16. public class javassistGenerator {  
  17.   
  18.     public static void main(String[] args) throws Exception{  
  19.         // 创建类     
  20.         ClassPool pool = ClassPool.getDefault();  
  21.         CtClass cls = pool.makeClass("com.cn.alal.TestClass");  
  22.           
  23.          // 添加私有成员name及其getter、setter方法     
  24.         CtField param = new CtField(pool.get("java.lang.String"), "name", cls);    
  25.   
  26.         param.setModifiers(Modifier.PRIVATE);    
  27.         cls.addMethod(CtNewMethod.setter("setName", param));    
  28.         cls.addMethod(CtNewMethod.getter("getName", param));    
  29.         cls.addField(param, Initializer.constant(""));    
  30.           
  31.         // 添加有参的构造体     
  32.         CtConstructor  cons = new CtConstructor(new CtClass[] {pool.get("java.lang.String")}, cls);    
  33.         cons.setBody("{$0.name = $1;}");    
  34.         cls.addConstructor(cons);    
  35.             
  36.         // 打印创建类的类名     
  37.         System.out.println(cls.toClass());  
  38.           
  39.         // 通过反射创建无参的实例,并调用getName方法     
  40.         Object o = Class.forName("com.cn.alal.TestClass").newInstance();    
  41.         Method getter = o.getClass().getMethod("getName");    
  42.         System.out.println(getter.invoke(o));    
  43.             
  44.         // 调用其setName方法     
  45.         Method setter = o.getClass().getMethod("setName"new Class[] {String.class});    
  46.         setter.invoke(o, "Adam");    
  47.         System.out.println(getter.invoke(o));    
  48.             
  49.         // 通过反射创建有参的实例,并调用getName方法     
  50.         o = Class.forName("com.cn.alal.TestClass").getConstructor(String.class).newInstance("Liu Jian");    
  51.         getter = o.getClass().getMethod("getName");    
  52.         System.out.println(getter.invoke(o));    
  53.   
  54.   
  55.     }  
  56.   
  57. }  

猜你喜欢

转载自blog.csdn.net/liao1990/article/details/80633294