1、简介

Javassist(JAVA programming ASSISTant)是在Java中编辑字节码的类库;它使Java程序能够在运行时定义一个新类,并在JVM加载是修改类文件。

我们常用到的动态特性主要是反射,在运行时查找对象属性、方法,修改作用域,通过方法名称调用方法等。在线的应用不会频繁使用反射,因为反射的性能开销较大。其实还有一种和反射一样强大的特性,但是开销却很低,他就是Javassist。

与其他类似的字节码编辑器不同,Javassist提供了两个级别的API:源级别和字节码级别。如果用户使用源级API,他们可以编辑类文件,而不知道Java字节码的规格。整个API只用Java语言的词汇来设计。您甚至可以以源文本的形式指定插入的字节码;Javassist在运行中编译它。另一方面,字节码级API允许用户直接编辑类文件作为其他编辑器。

2、读取和写入字节码

类Javassist.CtClass是类文件的抽象表示形式。CtClass(编译时类)对象是处理类文件的句柄。下面的程序是一个非常简单的示例:

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("test.Rectangle");
cc.setSuperclass(pool.get("test.Point"));
cc.writeFile();

该程序首先获得一个ClassPool对象,它通过Javassist对象字节码修改。ClassPool对象是表示类文件的CtClass对象的容器。它根据需要读取类文件以构造CtClass对象,并记录构造对象以响应以后的访问。若要修改类的定义,用户必须首先从ClassPool对象获取对表示该类的CtClass对象的引用。ClassPool对象获得的,它被分配给一个变量cc。getDefault返回的ClassPool对象搜索默认的系统搜索路径。

可以修改从ClassPool对象获得CtClass对象(稍后将介绍如何修改CtClass的详细信息)。在上面的例子中,它被修改以便测试的超类。将矩形更改为类测试点。当最终调用CtClass()中的writeFile()时,此更改将反映在原始类文件中。

writeFile()时,此更改将反映在原始类文件中。

writeFile()将CtClass对象转换为类文件,并将其写入本地磁盘。Javassist还提供了一种直接获取修改后的字节码的方法。要获取字节码,请调用toBytecode():

byte[] b = cc.toBytecode();

您还可以直接加载CtClass:

Class clazz = cc.toClass();

toClass()请求当前线程的上下文类加载程序加载由CtClass表示的类文件。它返回一个表示已加载类的java.lang.Class对象。

2.1、定义类

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeCLass("Point");

此程序定义一个类Point,包括没有成员。可以使用CtNewMethod中声明的工厂方法创建点的成员方法,并在CtClass中追加到点与addMethod()。

makeClass()无法创新接口;可以使用 makeInterface () 做。接口中的成员方法可以在 CtNewMethod 中使用 abstractMethod () 创建。请注意, 接口方法是一种抽象方法。

2.2、冻结类

如果CtClass对象由writeFile()、toClass()或toBytecode()转换为类文件,Javassist将冻结该CtClass对象。那CtClass对象的进一步修改不被允许。这是为了在开发人员试图修改已加载的类文件时发出警告,因为JVM不允许重新加载类。

冻结的CtClass可以解冻,一遍允许对类定义进行修改。例如,

CtClass cc = ...;cc.writeFile();
cc.defrost();
cc.setSuperclass(...);  // OK since the class is not frozen.

2.3、类搜索路径

静态方法ClassPool.getDefault()返回的默认ClassPool将搜索底层JVM(Java虚拟机)具有的同一路径。如果某个程序在web应用程序服务器(如JBoss和Tomcat)上运行,则ClassPool对象可能无法找到用户类,因为这样的web应用程序服务器使用多个类加载器以及系统类加载程序。在这种情况下,必须将附加的类路径注册到ClassPool。假设池引用的是ClassPool对象:

pool.insertClassPath(new ClassClassPath(this.getClass()));

此语句注册用于加载次饮用的对象的类的类路径。可以将任何类对象用作参数而不是this.getClass()。用于加载由该类对象表示的类的类路径已注册。可以将目录名注册为类搜索路径。例如,下面的代码将目录/usr/local/javalib添加到搜索路径中:

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath("/usr/local/javalib");

用户可以添加的搜索路径不仅是一个目录,而且可以是一个URL:

ClassPool pool = ClassPool.getDefault();
ClassPath cp - new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist.");
pool.insertClassPath(cp);

此程序将"http://www.javassist.org:80/java/"添加到类搜索路径中。此URL仅用于搜索属于包组织javassist的类。例如,要加载类org.javassist.test.Main,将从以下内容获取其类文件:

http://www.javassist.org:80/java/org/javassist/test/Main.class

此外,您可以直接给ClassPool对象一个字节数组,并从该数组构造一个CtClass对象。为此,请使用ByteArrayClassPath.例如:

ClassPool cp = ClassPool.getDefault();
byte[] b = a byte array;
String name = class name;
cp.insertClassPath(new ByteArrayClassPath(name, b));
CtClass cc = cp.get(name);

获得的CtClass对象表示由b指定的类文件定义的类。ClassPool从给定的ByteArrayClassPath读取类文件(如果调用了get(),并且给定的类名为get()等于名称指定的类别。

如果您不知道该类的完全限定名,则可以在ClassPool中使用makeClass():

ClassPool cp = ClassPool.getDefault();
InputStream ins = an input stream for reading a class file;
CtClass cc = cp.makeClass(ins);

makeClass()从给定输入流返回构造的CtClass对象。您可以使用makeClass()将类文件送到ClassPool对象。如果搜索路径包含大jar文件,这可能会提高性能。由于ClassPool对象根据需要读取类文件,因此它可能会反复搜索每个类文件的整个jar文件。makeClass()可用于优化此搜索。由makeClass()构造的CtClass保存在ClassPool对象中,不再读取类文件。

3、小结

本文简要介绍了javaassist及其简单用法。会有一些读者好奇:它和AOP有什么关系和区别?举个简单的例子即可:CGLib是动态代理的经典类库,其底层实现使用ASM,javaassist是类似ASM的东东。

4、参考文献

  1. javassist
  2. Java动态编程初探——Javassist

Javaassist简介相关推荐

  1. etcd 笔记(01)— etcd 简介、特点、应用场景、常用术语、分布式 CAP 理论、分布式原理

    1. etcd 简介 etcd 官网定义: A highly-available key value store for shared configuration and service discov ...

  2. Docker学习(一)-----Docker简介与安装

    一.Docker介绍 1.1什么是docker Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源 Docker可以让开发者打包他们的应用以及依赖包到一个轻量级,可移植 ...

  3. 【Spring】框架简介

    [Spring]框架简介 Spring是什么 Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:反转控制)和AOP(Asp ...

  4. TensorRT简介

    TensorRT 介绍 引用:https://arleyzhang.github.io/articles/7f4b25ce/ 1 简介 TensorRT是一个高性能的深度学习推理(Inference) ...

  5. 谷粒商城学习笔记——第一期:项目简介

    一.项目简介 1. 项目背景 市面上有5种常见的电商模式 B2B.B2C.C2B.C2C.O2O B2B 模式(Business to Business),是指商家和商家建立的商业关系.如阿里巴巴 B ...

  6. 通俗易懂的Go协程的引入及GMP模型简介

    本文根据Golang深入理解GPM模型加之自己的理解整理而来 Go协程的引入及GMP模型 一.协程的由来 1. 单进程操作系统 2. 多线程/多进程操作系统 3. 引入协程 二.golang对协程的处 ...

  7. Linux 交叉编译简介

    Linux 交叉编译简介 主机,目标,交叉编译器 主机与目标 编译器是将源代码转换为可执行代码的程序.像所有程序一样,编译器运行在特定类型的计算机上,输出的新程序也运行在特定类型的计算机上. 运行编译 ...

  8. TVM Operator Inventory (TOPI)简介

    TOPI简介 这是 TVM Operator Inventory (TOPI) 的介绍.TOPI 提供了比 TVM 具有更高抽象的 numpy 风格的,通用操作和调度.TOPI 如何在 TVM 中,编 ...

  9. 计算机视觉系列最新论文(附简介)

    计算机视觉系列最新论文(附简介) 目标检测 1. 综述:深度域适应目标检测标题:Deep Domain Adaptive Object Detection: a Survey作者:Wanyi Li, ...

最新文章

  1. 有关无人驾驶汽车的思考
  2. L1相对于L2较稀疏的原因
  3. Linux实验三父子进程每隔3秒,实验三进程的创建和简单控制(学生分析.doc
  4. x86服务器当虚拟化的存储,X86服务器虚拟化实施方案.doc
  5. 被忽视的代码审查,往往可以事半功倍?
  6. 拓端tecdat|R语言实现拟合神经网络预测和结果可视化
  7. JavaScript return的作用
  8. 尚硅谷视频分享_硅谷的女儿分享了她的“书呆子”故事
  9. CSS模块、筛选模块、文档处理(CUD)模块、事件模块
  10. Java并发基础知识,我用思维导图整理好了
  11. TestOpenWriter
  12. 深入理解计算机系统(第三版)家庭作业 第八章
  13. 卸载antivirus(AVG)教程
  14. 软件设计师必考精华 - 多媒体、信息安全、法律
  15. 已知有十六支男子足球队,参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。
  16. Bugly 之热修复学习
  17. 某些函数改为了inline方式优化。开始写CCursor类。
  18. 51单片机~串口通信(讲解+代码)
  19. 2022北京眼博会,中国国际青少年眼健康产业展会,近视矫正展
  20. 邓应海:4.2本周黄金提前休市,下周开盘需警惕

热门文章

  1. 我的博客即将同步至腾讯云+社区
  2. webservice和socket服务的区别
  3. 蓝桥练习-算法训练 审美课
  4. 【自定义排序规则】剑指 Offer 45. 把数组排成最小的数
  5. CSS过渡属性transitions详细解读——Web前端系列学习笔记
  6. Benelux Algorithm Programming Contest 2016 Preliminary 题解
  7. 关于ensp配置出现 Error: Please renew the default configurations.
  8. 现实生活中常用的动态路由OSPF(单区)
  9. 嵌入式论文3000字_SCI英文论文一般多少字
  10. linux crontab不运行,Linux运维知识之解决Linux中crontab不执行ntpdate问题