javassist入门

javassist的基本功能

Javassist是一个动态类库,可以用来检查、”动态”修改以及创建 Java类。其功能与jdk自带的反射功能类似,但比反射功能更强大。

重要的类

ClassPool:javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类,它的工作方式与 JVM 类装载器非常相似,
CtClass: CtClass提供了检查类数据(如字段和方法)以及在类中添加新字段、方法和构造函数、以及改变类、父类和接口的方法。不过,Javassist 并未提供删除类中字段、方法或者构造函数的任何方法。
CtField:用来访问域
CtMethod :用来访问方法
CtConstructor:用来访问构造器

语法

使用javassist来编写的代码与java代码不完全一致,主要的区别在于 javassist提供了一些特殊的标记符(以 System.out.println(Argument1:+ 1); 其中的$1表示第1个参数.

示例

可以通过javassist来修改java类的方法,来修改其实现。如下所示:

      ClassPool classPool = ClassPool.getDefault();
      CtClass ctClass = classPool.get("org.light.lab.JavassistTest");
      CtMethod ctMethod = ctClass.getDeclaredMethod("test");
      ctMethod.setBody("System.out.println(\"this method is changed dynamically!\");");
      ctClass.toClass();

上面的方法即是修改一个方法的实现,当调用ctClass.toClass()时,修改后的类将被当前的ClassLoader加载并实例化。

完整的代码:

public class ChangeDemo {

  public static void main(String[] args) throws NotFoundException, CannotCompileException {
       replaceMethodBody("foo.Student", "execute", "System.out.println(\"this method is changed dynamically!\");");
       Student student = new Student();
       student.execute();
   }

public static void replaceMethodBody(String clazzName, String methodName, String newMethodBody) {
    try {
        CtClass clazz = ClassPool.getDefault().get(clazzName);
        CtMethod method = clazz.getDeclaredMethod(methodName);
        method.setBody(newMethodBody);
        clazz.toClass();
    } catch (NotFoundException | CannotCompileException e) {
       throw new RuntimeException(e);
    }
}

}

限制与局限性

  • 需要注意的是,在调用ctClass.toClass()时,会加载此类,如果此类在之前已经被加载过,则会报一个duplicate load的错误,表示不能重复加载一个类。所以,修改方法的实现必须在修改的类加载之前进行。
  • 不能访问块之外的局部变量。如果在一个方法的开始和结尾都增加了代码段,那么在方法的结尾块中无法访问方法开始中的代码段中的变量(不太完美的解决方法是将原方法改名,然后再增加与原方法同名的方法)。

与aspectj的区别

使用aspectj也可以同样达到修改的效果,不过修改指定的类,则需要为修改这个类添加一个aspect,然后将这个aspect加入配置文件中以使其生效,比起javassist来说,修改一个类还是使用javassist相对简单一点。

容器中的Classpath

在tomcat之类的容器中是无法通过ClassPool.getDefault()获取到用户定义的类的,可以通过以下方法获取:
pool.insertClassPath(new ClassClassPath(this.getClass()));
或者:
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(“/usr/local/javalib”);

参考资料:

http://www.ibm.com/developerworks/cn/java/j-dyn0916/
http://jboss-javassist.github.io/javassist/tutorial/tutorial.html

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值