Java中的Javassist怎么使用

开篇

说起 aop 小伙伴们肯定很熟悉,无论是 jdk 动态代理或者是 cglib 等,其底层都是通过操作 java 字节码来实现代理。asm、aspectj和javassist等是常用的操作字节码的技术。

ASM 其设计和实现是尽可能小而且快,更专注于性能。它在指令的层面来操作,所以使用它需要对 JVM 的指令有所了解,门槛较高,CGLIB 就使用了 ASM 技术。

AspectJ 扩展了 Java 语言,定义了一系列 AOP 语法,在 JVM 中运行需要使用特定的编译器生成遵守 Java 字节码规范的 Class 文件,Spring AOP 使用了 AspectJ 。

Javassist 直接使用 Java 编码的形式操作字节码,简单易上手,性能高于反射,相比于 ASM 稍低。

Javassist 常用类

Javassist 抽象出一个 ClassPool 对象来操作 Java 类,可以通过 ClassPool.getDefault() 来获取默认的 ClassPool 。常用的对象:

立即学习“Java免费学习笔记(深入)”;

CtClass:代表一个 Class 的实例,可以通过类的全限定名来获取 CtClass 对象,其中包含了对 Class 的各种操作。

ClassPool:通过 HashTable 保存了路径下的 CtClass 信息,key为类的全限定名称,value 为类名对应的 CtClass 对象。

CtMethod、CtField:抽象出类的方法和属性,可以用于定义或修改方法和字段。

Javassist 的使用

依赖

  org.javassist  javassist  3.27.0-GA

登录后复制

代码示例

// 获取默认类池  ClassPool classPool = ClassPool.getDefault();  // 1. 创建空类  CtClass ctClass = classPool.makeClass("com.aysaml.demo.javassist.User");  // 2. 创建 String 类型的 name 字段  CtField field = new CtField(classPool.get("java.lang.String"), "name", ctClass);  // 设置字段访问级别 private  field.setModifiers(Modifier.PRIVATE);  // 增加字段  ctClass.addField(field);  // 3. 增加 getter & setter 方法  ctClass.addMethod(CtNewMethod.getter("getName", field));  ctClass.addMethod(CtNewMethod.setter("setName", field));  // 4. 增加无参构造方法:其中 $0 表示 this,$1 表示参数  CtConstructor noArgsCons = new CtConstructor(new CtClass[] {}, ctClass);  noArgsCons.setBody("{$0.name="mark";}");  ctClass.addConstructor(noArgsCons);  // 5. 增加有参构造方法  CtConstructor hasArgsCons =    new CtConstructor(new CtClass[] {classPool.get("java.lang.String")}, ctClass);  hasArgsCons.setBody("{$0.name=$1;}");  ctClass.addConstructor(hasArgsCons);  // 6. 创建方法  CtMethod method = new CtMethod(CtClass.voidType, "printName", new CtClass[] {}, ctClass);  method.setBody("{System.out.println($0.name);}");  ctClass.addMethod(method);  // 7. 生成类文件:可指定路径,默认为当前项目根目录  ctClass.writeFile();  // 8. 创建类实例  Object person = ctClass.toClass().newInstance();

登录后复制

如何实现类似 AOP 的功能

javassist 对于编程化的操作字节码是很简单易懂的,我们以在方法的开头结尾打印信息为例:

public class Cat { /** 记录喵喵喵的次数 */ private int num; public void miao() {  this.num++; }}

登录后复制

我们要在 miao( ) 方法的前增加声音输出:

public static void main(String[] args) throws NotFoundException, CannotCompileException {  ClassPool classPool = ClassPool.getDefault();  // 获取 Cat 类的 CtClass 对象  CtClass catClass = classPool.get("com.aysaml.demo.javassist.Cat");  // 获取 miao( ) 方法  CtMethod method = catClass.getDeclaredMethod("miao");  method.insertBefore("System.out.println("miao~");");  // 加载修改过的类,注意必须要保证调用前这个类没有被加载过  catClass.toClass();  //测试  Cat cat = new Cat();  cat.miao(); }

登录后复制

注意到,在使用 catClass.toClass() 加载被修改过的类时,强调必须保证在调用前这个类没有被加载过,否则会报 attempted duplicate class definition for name 异常。

我们知道一个类是不能被一个类加载器加载两次的,所以为了解决这个问题,需要制定一个没有加载过该类的 Classloader,Javassist 提供了一个 ClassLoader ,如下:

public class Cat { /** 记录喵喵喵的次数 */ private int num; public void miao() {  System.out.println("调用了 miao 方法");  this.num++; } public static void main(String[] args) throws Exception{  ClassPool classPool = ClassPool.getDefault();  // 获取 Cat 类的 CtClass 对象  CtClass catClass = classPool.get("com.aysaml.demo.javassist.Cat");  // 获取 miao( ) 方法  CtMethod method = catClass.getDeclaredMethod("miao");  method.insertBefore("System.out.println("miao~");");  // 重新设置一个 Classloader  Loader classLoader = new Loader(classPool);  Class clazz = classLoader.loadClass("com.aysaml.demo.javassist.Cat");  // 调用修改过的类的方法  clazz.getDeclaredMethod("miao").invoke(clazz.newInstance()); }}

登录后复制

执行结果为:

Java中的Javassist怎么使用

以上就是Java中的Javassist怎么使用的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2626210.html

(0)
上一篇 2025年3月7日 00:50:31
下一篇 2025年2月25日 19:00:55

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Java怎么在CompletableFuture中实现日志记录

    1.首先利用aop为所有请求入口添加requestid。 @Aspect@Componentpublic class LoggingAspect {    /**     * AOP注解的Controller类方法必须为 public 或 …

    编程技术 2025年3月7日
    200
  • Java如何实现优雅的参数校验

    一、引子 要对方法的参数进行校验,最简单暴力的写法是这个样子:     public static void utilA(String a,BigDecimal b){        if (StringUtils.isEmpty(a)){…

    2025年3月7日
    200
  • Java之SpringBoot怎么实现基本增删改查

    根据上图所示,idea中我们有7个比较重要的模块需要建立 (1)controller包:如果学习过或者对SpringMVC有所了解的小伙伴,肯定知道,controller是控制层,相当于我们的接收浏览器信息并响应发送相关信息的地方,具体的还…

    2025年3月7日 编程技术
    200
  • Java SpringMVC数据响应实例分析

    1)页面跳转   直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。  返回带有前缀的字符串: 转发:   forward:/WEB-INF/views/index.jsp 重定向:   redirect:/index…

    2025年3月7日
    200
  • Java反射怎么定义和使用

    定义 在java程序运行期间动态获取和操作类、方法、属性等元素的能力被称为java反射。它使得我们可以在程序运行时获取一个类的信息,并对其进行操作,这极大地扩展了java语言的灵活性和可扩展性。 在Java中,每个类都有一个对应的Class…

    编程技术 2025年3月7日
    200
  • Java Agent怎么用

    Java Agent 技术简介 java agent 直译为 java 代理,也常常被称为 java 探针技术。 Java Agent 这种技术是在 JDK1.5 引入的,可以在运行时动态修改 Java 字节码。Java 中的类编译后形成字…

    2025年3月7日 编程技术
    200
  • Java Spring怎么实现定时任务

    java实现定时任务 jdk自带的库中,有两种方式可以实现定时任务,一种是timer,另一种是scheduledthreadpoolexecutor。 Timer+TimerTask 创建一个Timer就创建了一个线程,可以用来调度Time…

    2025年3月7日
    200
  • Java 中的异构系统集成和数据集成技术

    随着大数据和云计算技术的发展,企业和组织面临着多种异构系统的集成和数据交换的挑战。在这个背景下,java 的异构系统集成和数据集成技术得到了广泛的应用和发展。本文将从异构系统集成和数据集成的概念、java 中异构系统集成和数据集成的原理和应…

    编程技术 2025年3月7日
    200
  • Java 中的移动支付和金融科技技术

    随着人们生活方式和消费习惯的变化,移动支付和金融科技在全球范围内正在迅速发展。作为一种新兴的支付方式,移动支付已经成为了人们生活中不可或缺的一部分。java 作为一种强大的编程语言,在移动支付和金融科技领域也有着重要的作用。 移动支付的核心…

    编程技术 2025年3月7日
    200
  • Java 中的区块链和数字货币技术

    区块链和数字货币技术是如今最热门的技术之一,文章将对java中的区块链和数字货币技术进行探讨。 区块链是一个由多个块组成的链式结构网络,每个块存储着许多交易信息。 在Java中,区块链可以通过使用Spring Boot和Web3J等框架来实…

    编程技术 2025年3月7日
    200

发表回复

登录后才能评论