文档章节

Javassist使用方法总结

GameKing
 GameKing
发布于 2016/11/26 01:07
字数 1394
阅读 1558
收藏 16

一.    API相关

    最近使用Javassist框架开发了一些功能,使用的过程中碰见了不少问题,将使用方法总结下,以防日后重复踩坑。

    先来看一段代码:

ClassPool classPool = ClassPool.getDefault();
classPool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader()));
CtClass ctClass = classPool.getCtClass("cn.com.Test");
CtMethod ctMethod = CtNewMethod.make("public void helloWorld(){ System.out.println(\"hello world!\"); }", ctClass);
ctClass.addMethod(ctMethod);
ctClass.toClass();

    这段代码的功能很简单,在创建了一个默认的classpool后,加入当前线程的上下文类加载器作为额外的类搜索路径,获取Test类后向其中加入了helloWorld这个方法,并把修改后的类加载至当前线程所在的上下文类加载器中。

    可以发现利用javassist框架进行动态编程是比较轻松简单的,来看几个比较重要的API:

ClassPool

    ClassPool是CtClass对象的容器,每一个CtClass对象都必须从ClassPool中获取。

    ClassPool自身可以形成层级结构,其工作机制与java的类加载器类似,只有当父节点找不到类文件时,才会调用子节点的get()方法。通过设置 ClassPath.childFirstLookup 属性可以调整其工作流程。

    需要注意的是ClassPool会在内存中维护所有被它创建过的CtClass,当CtClass数量过多时,会占用大量的内存,API中给出的解决方案是周期性的调用compress方法 或 重新创建ClassPool 或 有意识的调用CtClass的detach()方法以释放内存

    需要关注的方法:

        1.    getDefault : 返回默认的ClassPool,单例模式!一般通过该方法创建我们的ClassPool。

        2.    appendClassPath, insertClassPath  : 将一个ClassPath加到类搜索路径的末尾位置 或 插入到起始位置。通常通过该方法写入额外的类搜索路径,以解决多个类加载器环境中找不到类的尴尬。

        3.    toClass : 将修改后的CtClass加载至当前线程的上下文类加载器中,CtClass的toClass方法是通过调用本方法实现。需要注意的是一旦调用该方法,则无法继续修改已经被加载的class。

        4.    get , getCtClass : 根据类路径名获取该类的CtClass对象,用于后续的编辑。

ClassPath

    ClassPath是一个接口,代表类的搜索路径,含有具体的搜索实现。当通过其它途径无法获取要编辑的类时,可以尝试定制一个自己的ClassPath。API提供的实现中值得关注的有:

        1.    ByteArrayClassPath : 将类以字节码的形式加入到该path中,ClassPool 可以从该path中生成所需的CtClass。

        2.    ClassClassPath : 通过某个class生成的path,通过该class的classloader来尝试加载指定的类文件。

        3.    LoaderClassPath : 通过某个classloader生成path,并通过该classloader搜索加载指定的类文件。需要注意的是该类加载器以弱引用的方式存在于path中,当不存在强引用时,随时可能会被清理。

CtClass

    javassist为每个需要编辑的class都创建了一个CtClass对象,通过对CtClass对象的操作来实现对class的编辑工作。

    该类方法较多,此处列出需要重点关注的方法:

        1.    freeze : 冻结一个类,使其不可修改。

        2.    isFrozen : 判断一个类是否已被冻结。

        3.    prune : 删除类不必要的属性,以减少内存占用。调用该方法后,许多方法无法将无法正常使用,慎用。

        4.    defrost : 解冻一个类,使其可以被修改。如果事先知道一个类会被defrost, 则禁止调用 prune 方法。

        5.    detach : 将该class从ClassPool中删除。

        6.    writeFile : 根据CtClass生成 .class 文件。

        7.    toClass : 通过类加载器加载该CtClass。

CtMethod

    CtMthod代表类中的某个方法,可以通过CtClass提供的API获取或者CtNewMethod新建,通过CtMethod对象可以实现对方法的修改。

    需要注意的是写入方法体的代码无法访问在其它地方定义的成员变量,一些比较重要的方法:

        1.    insertBefore : 在方法的起始位置插入代码。

        2.    insterAfter : 在方法的所有 return 语句前插入代码以确保语句能够被执行,除非遇到exception。

        3.    insertAt : 在指定的位置插入代码。

        4.    setBody : 将方法的内容设置为要写入的代码,当方法被 abstract修饰时,该修饰符被移除。

        5.    make : 创建一个新的方法。

CtNewMethod

    提供各种静态方法来操作CtMethod,不进行详细描述,有兴趣可以看下API。

特殊符号

$0, $1, $2, ... this and actual parameters
$args An array of parameters. The type of $args is Object[].
$$ All actual parameters.For example, m($$) is equivalent to m($1,$2,...)
$cflow(...) cflow variable
$r The result type. It is used in a cast expression.
$w The wrapper type. It is used in a cast expression.
$_ The resulting value
$sig An array of java.lang.Class objects representing the formal parameter types
$type A java.lang.Class object representing the formal result type.
$class A java.lang.Class object representing the class currently edited.

  •  

二.    使用场景总结

    1.    实现代码插入功能:

CtClass ctClass = classPool.getCtClass("com.netease.HelloWorld");
CtMethod ctMethod = ctClass.getDeclaredMethod("sayHello");
ctMethod.insertAfter("System.out.println(\"Hello world!\");");
ctClass.toClass();

    2.    创建一个完整的类:

ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass("com.netease.Class");

CtField ctField = new CtField(classPool.get("java.lang.String"), "teacher", ctClass);
ctField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ctField);

ctClass.addMethod(CtNewMethod.setter("setTeacher", ctField));
ctClass.addMethod(CtNewMethod.getter("getTeacher", ctField));
ctClass.writeFile();

    3.    实现拦截器功能:

CtMethod ctMethod = clazz.getDeclaredMethod(method);
String newName = method + "New";
ctMethod.setName(newName);
CtMethod newCtMethod = CtNewMethod.copy(ctMethod, method, clazz, null);
String type = ctMethod.getReturnType().getName();
StringBuilder body = new StringBuilder();
body.append("{\n System.out.println(\"Before Method Execute...\");\n");
if(!"void".equals(type)) {
    body.append(type).append(" result = ");
}
body.append(newName).append("($$);\n");
body.append("System.out.println(\"After Method Execute...\");;\n");
if(!"void".equals(type)) {
    body.append("return result;\n");
}
body.append("}");
newCtMethod.setBody(body.toString());
clazz.addMethod(newCtMethod);

 

© 著作权归作者所有

共有 人打赏支持
GameKing
粉丝 22
博文 20
码字总数 20400
作品 1
杭州
程序员
私信 提问
iYoungDone/CharlesLoader

查尔斯动态加载启动器(CharlesLoader) Charles v4.x 查尔斯动态加载启动器(CharlesLoader) #####使用方法: Windows系统下,请将out/win目录下的CharlesLoader.jar和run-charlesloader.bat两个...

iYoungDone
2017/05/11
0
0
Java 编程的动态性, 第四部分: 用 Javassist 进行类转换

讲过了 Java 类格式和利用反射进行的运行时访问后,本系列到了进入更高级主题的时候了。本月我将开始本系列的第二部分,在这里 Java 类信息只不过是由应用程序操纵的另一种形式的数据结构而已...

银月光海
2015/04/14
0
0
javassist用法总结

1.1. Javassist介绍 Javassist是一个开源的分析、编辑和创建Java字节码的类库。它是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令...

xpbob
2015/11/24
97
0
mac Charles v4.0.2详细破解教程

背景 Charles是一款十分优秀的抓包软件,尤其是在mac操作系统下。Charles是一款商用软件,其体验版虽然能够使用全部功能,但是有以下几个使用上不方便的地方: 启动时有10s的提示购买窗口,并...

wooyoo
2016/12/18
0
0
Javassist

Javassist 火星信息安全研究院2018-01-041 阅读 JavaJavassist Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing byte......

火星信息安全研究院
2018/01/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用keepalived实现nginx的高可用

概述 是这样子的,我想让家中所有的应用服务都从nginx中出去,让nginx处于访问的最边缘地带,为了让nginx可靠性加强,所以nginx就得实现高可用,分别是下面两台机器要做nginx的集群 10.10.10...

bboysoulcn
今天
2
0
Mysql索引机制B+Tree

1、问题引入 有一个用户表,为了查询的效率,需要基于id去构建索引。构建索引我们需要考虑两个方面的问题,1个是查询的效率,1个是索引数据的存储问题。该表的记录需要支持百万、千万、甚至上...

万山红遍
今天
44
0
RDD

1.概念: RDD是spark整个体系中最基础核心的概念,RDD(Resilient Distributed DataSet)即弹性分布式数据集 弹性: RDD支持横向多分区,纵向操作内存不足写入磁盘,hdfs等,实现数据在内存和...

仟昭
今天
2
0
springboot整合mycat

动态数据源项目整合 Maven依赖信息 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relat......

须臾之余
今天
3
0
深入解析Vue 和微信小程序的区别、比较

写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别。 一、生命周期 先贴两张图: vue生命周期 小程序生命周期 相比之下,小程序的钩子函数要简单得多。 vue的...

前端攻城小牛
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部