ClassPool

ClassPool对象是一个CtClass对象的容器。一个CtClass对象被构建后,它被记录在ClassPool中。这是因为当编译的原文件关联到CtClass表示的类, 编译器要访问CtClass对象。

例如,假定一个新方法getter()要加入到CtClass对象表示的的Point类。程序试图编译Point中的方法getter()的源代码,用编译过的代码做为方法内容,将它加到另一个类Line中。如果CtClass对象表示的Point丢失了,编译器将不能编译getter()方法。注册初始的类不包含getter()方法。因此,为了正确的编译一个方法,ClassPool必须拥有程序运行时所有的CtClass实例。

避免内存溢出

ClassPool的特点决定了当 CtClass对象数量很多时,它所占的内存会非常大。为了避免这种情况发生,你可以明确的移除一个ClassPool中的不需要的CtClass对象。如果用CtClass的detach()方法,CtClass对象将从ClassPool中移除。例如:

CtClass cc = ... ;
cc.writeFile();
cc.detach();

执行deatach()后,将不能执行CtClass对象的任何方法。但是,可以执行ClassPool的get()方法得到表示同一个类的CtClass实例。执行get()后,ClassPool再次读取类文件,重新建立CtClass对象。

另一个办法是用新的ClassPool替换老的。如果老的 ClassPool当做垃圾被回收了,它里面的CtClass对象也会被回收,建立新的ClassPool实例,执行下面的代码片段:

       ClassPool cp = new ClassPool(true);
       // if needed, append an extra search path by appendClassPath()

通过ClassPool.getDefault()构建默认行为的ClassPool对象。注意ClassPool.getDefault()是为了方便提供的单子工厂方法。它保持着单独的对象并重用它。getDefault()返回的ClassPool对象没有特别的作用。getDefault()是一个方便的方法。

注意new ClassPool(true)是个方便的构造器,它构建一个ClassPool对象并加入系统搜索路径。执行它等同于下面的代码:

ClassPool cp = new ClassPool();
cp.appendSystemPath(); // or append another path by appendClassPath()

级联的ClassPools

如果程序运行在web服务器中,可能需要建立多个ClassPool;要为每个类载入器建一个ClassPool。程序将不用getDefault(),用ClassPool构造器建一个ClassPool对象。

多个CLassPool对象像java.lang.ClassLoader一样级联起来。例如,

       ClassPool parent = ClassPool.getDefault();
       ClassPool child = new ClassPool(parent);
       child.insertClassPath("./classes");

如果执行child.get(),孩子ClassPool首先去查找父ClassPool。如果说父查找失败,孩子再去./classes目录下查找类。

如果child.childFirstLookup为true,先在孩子中查找,再到父中查。例如:

  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.

改变类名,定义一个新类

一个新类可以被定义为已经存在类的拷贝。看下面的程序:

ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("Point");cc.setName("Pair");这个程序首先得到Point作为CtClass对象,然后用setName()为CtClass设置了新的名字Pair,之后CtClass对象的类名被改为Pari,类定义的其他部分没有变。  注意 CtClass的setName()改变了ClassPool中的一个记录。从实现的角度 ,setName()改变的是ClassPool 的hash表中的CtClass对象关联的key。Key从初始的类名改到了新类名。

因此,如果get(“Point”) 再次被执行后,将不能返回cc引用的CtClass对象。ClassPool再次读取Point.class类文件,为Point构建新的CtClass对象。这是因为Point命名的CtClass对象已经不存在了。看下面例子:

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.

Cc1和cc2引用同一个CtClass实例cc,而cc3不是。注意,cc.setName(“Pair”)执行后,CtClass对象Pair 被cc和cc1引用。

ClassPool对象用来维持类和CtClass对象之间一对一的关系映射。Javassist不允许用两个有区别的CtClass对象表示同一个类,除非建两个单独CLassPool。这是对程序转换前后有意义的功能。

建立另一个ClassPool默认实例的拷贝,用ClassPool.getDefault()得到,执行下面代码:

ClassPool cp = new ClassPool(true);如果有两个ClassPool对象,可以分别从ClassPool中得到表示同一个类文件的有区别的CtClass对象。可以编辑不同的CtClass对象用来生成不同的类的版本。  改变冻结类名,定义一个新类

当CtClass对象通过writeFile()或toBytecode()转换为类文件,Javassist将拒绝CtClass对象的修改。因此CtClass表示的Point类是被转换到类文件中了,执行setName()不能定义Pair类作为Point的拷贝,它将被拒绝。下面的代码是错误的:

ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("Point");cc.writeFile();cc.setName("Pair");   // wrong since writeFile() has been called.

为了避免这个限制,可以执行ClassPool的getAndRename()方法,例如:

ClassPool pool = ClassPool.getDefault();

CtClass cc = pool.get("Point");cc.writeFile();CtClass cc2 = pool.getAndRename("Point", "Pair"); 如果执行getAndRename(),ClassPool首先读取Point.class建立一个新的CtClass。但是,它重命名CtClass从Point改为Pair以前,要先在CtClass的Hash表中作记录。因此,writeFile()或toBytecode()执行后可以执行getAndRename()。

from: https://blog.csdn.net/qbg19881206/article/details/8992333

JavaSist之ClassPool相关推荐

  1. ClassPool CtClass浅析

    最近在看android中的热更新原理,里面有用到javassist来更改.class,因而又恶补了下ClassPool和CtClass的相关使用.虽然android中现在热更新是用 groovy, g ...

  2. javasist代码实现解析

    概述 Javassist是一个开源的分析.编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码.相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构, ...

  3. Javassist实战-修改现有类

    对于新增类应用场景不常见,而修改现有类应用场景更多,比如常见的日志切面,权限切面. 修改现有.class文件 已有类新增方法 1.现有类Person public class Person {priv ...

  4. JavaScript中文技术文档

    bytecode读写 ClassPool Class loader 自有和定制 Bytecode操控接口 Generics Varargs J2ME 装箱和拆箱 调试 bytecode读写 Javas ...

  5. fastjson 1.22-1.24 漏洞复现与分析

    fastjson 1.22-1.24 漏洞复现与分析 前言 QAQ,感觉自己啥也不会,要好好努力学习了.但是由于本人遗忘度很大,因此要记下来学习QAQ. 概念 RMI(Remote Method In ...

  6. Java字节码instrument研究

    MyAgent项目 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  7. javassist 初步学习

    javassist简介 javassist可以对一个已经编译好了的.class文件的字节码进行改动,比如说我可以为一个类添加一个方法,添加一个属性,也可以修改一个方法等,还可以对一个方法,异常进行拦截 ...

  8. javassist学习笔记

    2019独角兽企业重金招聘Python工程师标准>>> 介绍:www.javassist.org/ javassist.ASM 对比 1.javassist是基于源码级别的API比基 ...

  9. 动态代理竟然如此简单!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 这篇文章我们来聊一下 Java 中的动态代理. 动态代理在 ...

最新文章

  1. python3 基本数据类型
  2. 【资源分享】CS起源 V34.4044(经典版本)
  3. 博客园修改页面显示样式css
  4. 手游开发者交流会议暨OGEngine新版发布
  5. Linux网络管理实 验 指 导
  6. 防止Visual C++应用程序缓冲区溢出
  7. Direct2D (13) : 画刷之 ID2D1BitmapBrush
  8. Web前端JavaScript笔记(5)事件-拖拽
  9. 学号 20165329 《Java程序设计》第4周学习总结
  10. 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第5节 使用骨架创建maven的java工程_10idea集成maven插件...
  11. 卡方检验2-python代码实现
  12. PBRT-V3体渲染笔记
  13. IERS EOP 文件的解读
  14. 01背包, 完全背包,多重背包
  15. Xutils上传图片(2)
  16. 极视角与山东港口科技集团青岛有限公司共建「AI 赋能智慧港口联合实验室」
  17. 最简单DIY基于C#和51单片机上下位机一体化的PCA9685舵机控制程序
  18. TFS文件编码检查机制和修改(Team Foundation Server 2013)
  19. Python 3 怎么快速搭建服务器
  20. 中学教学参考杂志中学教学参考编辑部中学教学参考杂志社2022年第18期目录

热门文章

  1. windows下spark开发环境配置
  2. 【Python】常用包整理,包括Numpy、Pandas、sklearn、url、pymysql、Wxpy、Xlwt、Pyecharts等
  3. 大象狂奔,地表最强大的投行高盛摩根转型
  4. 百度发布机器人助理度秘 “三大基石”炼成
  5. 七牛技术总监陈超:记Spark Summit China 2015
  6. Make!Sense 动手好伴侣,带你轻松做实验
  7. c语言奇数值结点链表,习题11-7 奇数值结点链表 (20 分)
  8. mysql的主从项目经验_mysql5.5主从经验分享
  9. 架构漫谈 - 数据治理核心思路及解决方案探讨
  10. Oracle查询优化-07日期运算