Javassist使用指南1

2024-06-24 04:58
文章标签 java 使用指南 ssist

本文主要是介绍Javassist使用指南1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.创建了一个非默认的classpool,加入当前线程的上下文类加载器作为额外的类搜索路径

val classPool = ClassPool(false)
classPool.appendClassPath(LoaderClassPath(contextClassLoader))

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

lassPath是一个接口,代表类的搜索路径,含有具体的搜索实现。当通过其它途径无法获取要编辑的类时,可以尝试定制一个自己的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[].
A l l a c t u a l p a r a m e t e r s . F o r e x a m p l e , m ( All actual parameters.For example, m( Allactualparameters.Forexample,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);

这篇关于Javassist使用指南1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1089227

相关文章

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹

Java中的stream流分组示例详解

《Java中的stream流分组示例详解》Java8StreamAPI以函数式风格处理集合数据,支持分组、统计等操作,可按单/多字段分组,使用String、Map.Entry或Java16record... 目录什么是stream流1、根据某个字段分组2、按多个字段分组(组合分组)1、方法一:使用 Stri

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

Spring创建Bean的八种主要方式详解

《Spring创建Bean的八种主要方式详解》Spring(尤其是SpringBoot)提供了多种方式来让容器创建和管理Bean,@Component、@Configuration+@Bean、@En... 目录引言一、Spring 创建 Bean 的 8 种主要方式1. @Component 及其衍生注解