原文链接

上一章:

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的更多相关文章

  1. Javassist指引(一)

    目录 原文链接 1. 读写字节码 1.1概述 Javassist是一个Java字节码类库.Java的字节码是包含Java类与接口,并按照一定的顺序存在class文件中. Javassist.CtCla ...

  2. 字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一篇 Helloworld 中,我们初步尝试使用了 Javassist字节编程的 ...

  3. tornado用户指引(二)------------tornado协程实现原理和使用(一)

    摘要:Tornado建议使用协程来实现异步调用.协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现.(在linux基于epoll的异步调用中,我们需要 ...

  4. 字节码类库之Javassist

    Javassist优势 – 比反射开销小,性能高.–javassist性能高于反射,低于ASM运行时操作字节码可以让我们实现如下功能:– 动态生成 新的类– 动态改变某个类的结构 ( 添加 / 删除 ...

  5. 跟我一起造轮子 手写springmvc

    原创地址:https://www.cnblogs.com/xrog/p/9820168.html 作为java程序员,项目中使用到的主流框架多多少少和spring有关联,在面试的过程难免会问一些spr ...

  6. 通过微信服务号推送Zabbix告警

    近期看到一篇通过微信实现Zabbix告警的文章,但实践时发现,无法成功发送消息. 分析原因,应该是微信公众平台加强了登录验证,在登录时会需要管理员进行扫描二维码操作才能成功登陆后台: 而之前文章中的A ...

  7. Caused by: java.lang.ClassNotFoundException: javassist.ClassPool

    1.错误原因 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -nonaming ] { -help ...

  8. [转载]Javassist 使用指南(二)

    ======================= 本文转载自简书,感谢原作者!. 原链接如下:https://www.jianshu.com/p/b9b3ff0e1bf8 =============== ...

  9. Unity AssetBundles and Resources指引 (二) Resources文件夹

    本文内容主要翻译自下面这篇文章 https://unity3d.com/cn/learn/tutorials/topics/best-practices/guide-assetbundles-and- ...

随机推荐

  1. 【JZOJ5093】【GDSOI2017第四轮模拟day3】字符串匹配 哈希

    题面 对于一个字符集大小为C的字符串P,我们可以将任意两种字符在P中的位置进行互换,例如P=abcba,我们交换a,b就变为bacab,交换a,d就变为dbcbd,交换可以进行任意次.若交换后P变为了 ...

  2. Matlab 稀疏矩阵函数

    eye 单位矩阵zeros 全零矩阵ones 全1矩阵rand 均匀分布随机阵genmarkov 生成随机Markov矩阵linspace 线性等分向量logspace 对数等分向量logm 矩阵对数 ...

  3. python学习笔记09--线程、进程

    本节内容 一.进程与线程的概念 1.1进程 1.2线程 1.3进程与线程的区别 二.线程 2.1启一个线程 2.2线程的2种调用方式 2.3 join 2.4 守护线程Daemon 2.5线程锁 2. ...

  4. LeedCode --- Best Time to Buy and Sell Stock

    题目链接 题意: find the maximum positive difference between the price on the ith day and the jth day 附上代码: ...

  5. Sum Root to Leaf Numbers深度优先计算路径和

    Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...

  6. 【转载】遗传算法及matlab实现

    摘自https://www.cnblogs.com/LoganChen/p/7509702.html 1.遗传算法介绍 遗传算法,模拟达尔文进化论的自然选择和遗产学机理的生物进化构成的计算模型,一种不 ...

  7. Redis、MPP、kafka 、MongDB简介

    Redis :间值数据库,适合缓存用户Session会话与经常需要查的数据1.Redis集群,为什么在项目中使用集群  1.持久化,持久化是最简单的高可用方法(有时甚至不被归为高可用的手段),主要左右 ...

  8. KiCad 安装后没有元件怎么办?

    KiCad 安装后没有元件怎么办? 按以下步骤试试. 卸载 KiCad EDA. 按 Win+R 输入 %appdata%/kicad 进入 KiCad 的配置目录. 将里面的内容打包成一个 zip ...

  9. 2019-7-4-win10-uwp-处理用户点击关闭按钮

    title author date CreateTime categories win10 uwp 处理用户点击关闭按钮 lindexi 2019-07-04 09:28:57 +0800 2019- ...

  10. SaaS加速器II 能力中心:互利互补 共享商业红利

    摘要: 通过丰富的阿里集团和三方的业务能力API,缩短业务从0-1构建的周期和降低成本,我们希望能够把阿里巴巴在电商.金融.物流.高德以及其他领域沉淀出来商业最佳实践.商业能力,通过阿里云的渠道输出, ...