Javassist指引(二)--ClassPool
原文链接
上一章:
Javassist指引(一)
2.ClassPool
ClassPool是一个CtClass的容器。因为编译器随时可能访问一个CtClass类,所以一旦一个CtClass创建,它将永远保存在ClassPool类里面。
举一个简单的例子,之前我们有一个叫做表示Point类的CtClass实例,我们在里面添加了一个getter()方法。如果这个操作没有被永远地保存,在另外一处使用这个getter方法时又得重新添加。好在不是如此,ClassPool一直保存着这个实例。
2.1 避免OOM
因为ClassPool上述特性,随着CtClass越来越多,ClassPool的内存开销会越来越大。为了避免这个问题,我们可以移除一些不必要的CtClass类。我们调用CtClass::detach()方法执行这个操作。
CtClass ctClass = pool.makeClass(inputStream);
ctClass.writeFile();
ctClass.detach();
我们调用了detach后,就不能再调用CtClass的任何方法了。在Javassist3.0中,再次调用该命令会抛出RunTimeException.
另外一个方法是我们每次使用的时候手工创建一个ClassPool,旧的ClassPool在没有引用后就会被垃圾回收器回收,我们可以模仿ClassPool的getDefault方法。
ClassPool cp = new ClassPool();
//append ClassPath

的方法。
2.2级联ClassPools
如果这是一个Web程序,那么我们需要多个ClassPool,我们最好为每一个ClassLoader创建一个ClassPool。我们直接调用ClassPool的构造函数而非getDefault方法。
ClassPool parent = ClassPool.getDefault();
ClassPool child = new ClassPool(parent);
child.appendSystemPath(); // the same class path as the default one.
child.childFirstLookup = true; // changes the behavior of the child.
当我们调用child.get()的时候,程序会首先在parent ClassPool中需找结果,如果没有找到,会尝试在child ClassPool中寻找。
如果我们想优先在child ClassPool中寻找,我们可以将child.childFirstLookup设置为true
2.3改变类名以定义新类
通过改变一个已有的类的名字来定义新类,代码如下:
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.setName("Pair");
这段代码首先从ClassPool中取出一个CtClass,然后调用setName的方法。在这次调用后,类名将更改为Pair,但类的其他内容并未发生改变。(举个例子,如果先前有setX的方法,新类也有)。
需要注意的是,当我们调用setName的时候,将直接在原有类上做修改,不仅如此,先前我们提到ClassPool的实现是以name为key的HashTable,执行完setName之后,hashtable上面的key也会被改变。我们可以通过一段代码验证。
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
CtClass cc1 = pool.get("Point"); // cc1 is identical to cc.
cc.setName("Pair");
CtClass cc2 = pool.get("Pair"); // cc2 is identical to cc.
CtClass cc3 = pool.get("Point"); // cc3 is not identical to cc.
在Javassist中,一个ClassPool里面的name-object键值对都是1对1的关系。除非我们使用两个不同的ClassPool,Javassist不允许两个不同的CtClass拥有同一个类名。这个是Javassist的一个重要特征。
如果我们需要同一个类名有多个不同的版本,我们需要再创建一个ClassPool,然后修改新ClassPool中的CtClass。下面是一个例子。
ClassPool pool = ClassPool.getDefault();
ClassPool qool = new ClassPool();
qool.appendSystemPath();
2.4改变冻结类类名
当一个CtClass执行完writeFile或者toBytecode操作后,Javassist就会拒绝所有对这个CtClass的变更。上上述例子中,如果我们已经把Point冻结,那么我们执行setName将报错。
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.writeFile();
cc.setName("Pair"); // wrong since writeFile() has been called.

为了避开这个限制,我们可以调用getAndRename的方法,例如
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.writeFile();
CtClass cc2 = pool.getAndRename("Point", "Pair");
当我们调用getAndRename的时候,ClassPool会读取Point.class并创建对应的CtClass的类。然后再执行Rename的操作。
2.5 getAndRename
事实上,如果我们需要一个类的副本,最快捷的方法便是使用getAndRename,我们点进去getAndRename的实现,会发现这个操作的过程是重新从文件中再加载一遍该类,然后再添加进ClassPool。
我们通过一个简单的例子来看一下。
</div>
Javassist指引(二)--ClassPool的更多相关文章
- Javassist指引(一)
目录 原文链接 1. 读写字节码 1.1概述 Javassist是一个Java字节码类库.Java的字节码是包含Java类与接口,并按照一定的顺序存在class文件中. Javassist.CtCla ...
- 字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一篇 Helloworld 中,我们初步尝试使用了 Javassist字节编程的 ...
- tornado用户指引(二)------------tornado协程实现原理和使用(一)
摘要:Tornado建议使用协程来实现异步调用.协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现.(在linux基于epoll的异步调用中,我们需要 ...
- 字节码类库之Javassist
Javassist优势 – 比反射开销小,性能高.–javassist性能高于反射,低于ASM运行时操作字节码可以让我们实现如下功能:– 动态生成 新的类– 动态改变某个类的结构 ( 添加 / 删除 ...
- 跟我一起造轮子 手写springmvc
原创地址:https://www.cnblogs.com/xrog/p/9820168.html 作为java程序员,项目中使用到的主流框架多多少少和spring有关联,在面试的过程难免会问一些spr ...
- 通过微信服务号推送Zabbix告警
近期看到一篇通过微信实现Zabbix告警的文章,但实践时发现,无法成功发送消息. 分析原因,应该是微信公众平台加强了登录验证,在登录时会需要管理员进行扫描二维码操作才能成功登陆后台: 而之前文章中的A ...
- Caused by: java.lang.ClassNotFoundException: javassist.ClassPool
1.错误原因 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -help ...
- [转载]Javassist 使用指南(二)
======================= 本文转载自简书,感谢原作者!. 原链接如下:https://www.jianshu.com/p/b9b3ff0e1bf8 =============== ...
- Unity AssetBundles and Resources指引 (二) Resources文件夹
本文内容主要翻译自下面这篇文章 https://unity3d.com/cn/learn/tutorials/topics/best-practices/guide-assetbundles-and- ...
随机推荐
- OpenLayers添加地图标记
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...
- 学习JDK1.8集合源码之--TreeSet
1. TreeSet简介 TreeSet是Set的实现类之一,是不可重复集合,非线程安全的. TreeSet是SortedSet的唯一实现类,实现了元素的自动排序,排序不是以插入的顺序排序,而是默认以 ...
- typeid, const_cast<Type>的使用
#include <bits/stdc++.h> using namespace std; class A { public : void Show() { cout << & ...
- [C#] 如何分析stackoverflow等clr错误
有时候由于无限递归调用等代码错误,w3wp.exe会报错退出,原因是clr.exe出错了. 这种错误比较难分析,因为C#代码抓不住StackOverflowException等异常. 处理方法是:生成 ...
- Python中进制转换函数的使用
Python中进制转换函数的使用 关于Python中几个进制转换的函数使用方法,做一个简单的使用方法的介绍,我们常用的进制转换函数常用的就是int()(其他进制转换到十进制).bin()(十进制转换到 ...
- HZOJ matrix
完全没有思路,状压到死没调出来……吐槽一下这题目描述的好不清楚啊好多人都理解错题了…… 题解: 真的挺神仙的,因为有每列最多放1个的限制,所以考虑按列dp,设f[i][j]表示考虑前i列在[1,i]中 ...
- python基础之逻辑题(3)
Python基础之逻辑题(3) 1.编写一个函数实现将IP地址转换成一个整数 2.求结果:---lambda 3.求a的结果 4.求下面nums的输出 5.求下面片段的输出 6.写出程序的结果:--- ...
- python如何自动发送邮件
#coding=utf-8 import smtplib from email.mime.text import MIMEText from email.mime.application import ...
- ORACLE 创建pfile和spfile
使用服务器参数文件spfile创建文本参数文件pfile:1,SQL> create pfile from spfile="/u01/app/oracle/product/9. ...
- Python基础:28正则表达式
一:概述 正则表达式(RE)为高级文本模式匹配,以及搜索-替代等功能提供了基础.正则表达式(RE)是一些由字符和特殊符号组成的字符串,它们能匹配多个字符串.Python通过标准库的re模块支持正则表达 ...