javassist学习

article/2025/9/15 4:58:47

 

        Java 字节码以二进制的形式存储在 .class 文件中,每一个 .class 文件包含一个 Java 类或接口。Javaassist 就是一个用来 处理 Java 字节码的类库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深入的了解。同时也可以去生成一个新的类对象,通过完全手动的方式。

        在 Javassist 中,类 Javaassit.CtClass 表示 class 文件。一个 GtClass (编译时类)对象可以处理一个 class 文件

看代码示例:

加入依赖:

<dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.25.0-GA</version>
</dependency>

使用 Javassist 创建一个 class 文

代码:

package com.sqz.javassist;import javassist.*;import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class CreatePerson {public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {ClassPool pool = ClassPool.getDefault();CtClass ctClass = pool.makeClass("com.sqz.javassist.Persion");//增加成员变量CtField name = new CtField(pool.get("java.lang.String"), "name", ctClass);name.setModifiers(Modifier.PRIVATE);ctClass.addField(name,CtField.Initializer.constant("xiaoming"));ctClass.addMethod(CtNewMethod.setter("setName",name));ctClass.addMethod(CtNewMethod.getter("getName",name));//增加无参构造器CtConstructor noArgConstructor = new CtConstructor(new CtClass[]{}, ctClass);noArgConstructor.setBody("{name=\"xiaoming\";}");ctClass.addConstructor(noArgConstructor);//增加有参构造器CtConstructor ctConstructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, ctClass);// $0=this / $1,$2,$3... 代表方法参数ctConstructor.setBody("{$0.name=$1;}");ctClass.addConstructor(ctConstructor);//增加方法CtMethod printName = new CtMethod(CtClass.voidType, "printName", new CtClass[0], ctClass);printName.setModifiers(Modifier.PUBLIC);printName.setBody("{System.out.println(name);}");ctClass.addMethod(printName);//将生成的class输出到文件// ctClass.writeFile("/Users/mac/workspace/dubbo-dubbo-3.0.2/dubbo-demo-sqz/src/main/java/");//实例化对象并调用Object o = ctClass.toClass().newInstance();Method setName = o.getClass().getMethod("setName", String.class);Method getName = o.getClass().getMethod("getName");Method printName1 = o.getClass().getMethod("printName");setName.invoke(o,"老王");Object invoke = getName.invoke(o);System.out.println("getName->"+invoke);printName1.invoke(o);}}

运行上面代码会生成class文件

 class文件内容如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.sqz.javassist;public class Persion {private String name = "xiaoming";public void setName(String var1) {this.name = var1;}public String getName() {return this.name;}public Persion() {this.name = "xiaoming";}public Persion(String var1) {this.name = var1;}public void printName() {System.out.println(this.name);}
}

ClassPool需要关注的方法:

  1. getDefault : 返回默认的ClassPool 是单例模式的,一般通过该方法创建我们的ClassPool;
  2. appendClassPath, insertClassPath : 将一个ClassPath加到类搜索路径的末尾位置 或 插入到起始位置。通常通过该方法写入额外的类搜索路径,以解决多个类加载器环境中找不到类的尴尬;
  3. toClass : 将修改后的CtClass加载至当前线程的上下文类加载器中,CtClass的toClass方法是通过调用本方法实现。需要注意的是一旦调用该方法,则无法继续修改已经被加载的class
  4. get , getCtClass : 根据类路径名获取该类的CtClass对象,用于后续的编辑。

CtClass需要关注的方法:

  1. freeze : 冻结一个类,使其不可修改;
  2. isFrozen : 判断一个类是否已被冻结;
  3. prune : 删除类不必要的属性,以减少内存占用。调用该方法后,许多方法无法将无法正常使用,慎用;
  4. defrost : 解冻一个类,使其可以被修改。如果事先知道一个类会被defrost, 则禁止调用 prune 方法;
  5. detach : 将该class从ClassPool中删除;
  6. writeFile : 根据CtClass生成 .class 文件;
  7. toClass : 通过类加载器加载该CtClass。

CtMethod中的一些重要方法:

  1. insertBefore : 在方法的起始位置插入代码;
  2. insterAfter : 在方法的所有 return 语句前插入代码以确保语句能够被执行,除非遇到exception;
  3. insertAt : 在指定的位置插入代码;
  4. setBody : 将方法的内容设置为要写入的代码,当方法被 abstract修饰时,该修饰符被移除;
  5. make : 创建一个新的方法。

CtField中的一些重要方法 

  1. setModifiers: 在方法的起始位置插入代码;
  2. setGenericSignature: 在方法的所有 return 语句前插入代码以确保语句能够被执行,除非遇到exception;
  3. make : 创建一个新的方法。

 修改现有的类对象

代码如下

package com.sqz.javassist;public class UserService {public void printUser(){System.out.println("user");}}
z.javassist;import javassist.*;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class UpdatePerson {public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {ClassPool pool = ClassPool.getDefault();CtClass ctClass = pool.get("com.sqz.javassist.UserService");//修改方法 类似aopCtMethod printUser = ctClass.getDeclaredMethod("printUser");printUser.insertBefore("System.out.println(\"before\");");printUser.insertAfter("System.out.println(\"after\");");//增加方法CtMethod show = new CtMethod(CtClass.voidType, "show", new CtClass[0], ctClass);show.setBody("{System.out.println(\"show\");}");ctClass.addMethod(show);//增加字段 这种更简单CtField name = CtField.make("private String name = \"老王\";", ctClass);ctClass.addField(name);//增加方法CtMethod getName = CtNewMethod.make("public String getName() {\n" +"        return name;\n" +"    }", ctClass);ctClass.addMethod(getName);Object o = ctClass.toClass().newInstance();Method printUser1 = o.getClass().getMethod("printUser");printUser1.invoke(o);Method show1 = o.getClass().getMethod("show");show1.invoke(o);Method getName1 = o.getClass().getMethod("getName");Object invoke = getName1.invoke(o);System.out.println(invoke);}}

一般会遇到的使用场景应该是修改已有的类。比如常见的日志切面,权限切面等


http://chatgpt.dhexx.cn/article/23H6LkQn.shtml

相关文章

Javassist

Javassist Javassist是一个开源的分析、编辑和创建Java字节码的类库&#xff0c;可以直接编辑和生成Java生成的字节码。 相对于bcel, asm等这些工具&#xff0c;开发者不需要了解虚拟机指令&#xff0c;就能动态改变类的结构&#xff0c;或者动态生成类。javassist简单易用&…

[Java基础]—Javassist

Javassist Javassist (JAVA programming ASSISTant) 是在 Java 中编辑字节码的类库;它使 Java 程序能够在运行时定义一个新类, 并在 JVM 加载时修改类文件。原理与反射类似&#xff0c;但开销相对较低。 常用API ClassPool getDefault : 返回默认的 ClassPool 是单例模式的&…

Javassist基本用法

Javassist概述 Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类&#xff0c;并加载到JVM中&#xff1b;还可以在JVM加载时修改一个类文件&#xff0c;添加新的方法&#xff0c;或者是修改已有的方法。Javassist使用户不必关心字节码相关的规范…

Java中的高性能字节码工具:Javassist

前言 一般常见的动态方法调用使用Reflection或者字节码生成技术。虽然JDK已对反射进行了优化但在追求性能的场景中仍然显得性能不佳。本文即是介绍一个面向程序员友好的字节码操作类库javassist。根据benchmark其展现的性能已几乎无异于直接调用。 开源地址&#xff1a;javas…

Java字节码技术javassist

一、Javassist入门 &#xff08;一&#xff09;Javassist是什么 Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类&#xff0c;并加载到JVM中&#xff1b;还可以在JVM加载时修改一个类文件。Javassist使用户不必关心字节码相关的规范也是可以编…

java--javassist学习

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba &#xff08;千叶 滋&#xff09;所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jb…

javassist使用指南

目录 一、快速入门1.1 创建class文件1.2 ClassPool的相关方法1.3 CtClass的相关方法1.4 CtMethod的相关方法1.5 调用生成的类对象1.5.1 通过反射调用1.5.2 通过接口调用 1.6 修改现有的类对象 二、将类冻结三、类搜索路径四、$开头的特殊字符五、ProxyFactory的使用 我们知道Ja…

systemd介绍

由来 Linux 的启动一直采用init进程&#xff0c;这种方法有两个缺点。一是启动时间长。init进程是串行启动&#xff0c;只有前一个进程启动完&#xff0c;才会启动下一个进程&#xff0c;二是启动脚本复杂。init进程只是执行启动脚本&#xff0c;不管其他事情。脚本需要自己处理…

systemd man手册

SYSTEMD&#xff08;1&#xff09;systemd SYSTEMD&#xff08;1&#xff09; 名称 systemd&#xff0c;init-systemd系统和服务管理器 概要 /lib/systemd/systemd [OPTIONS...]init [OPTIONS...] {COMMAND}描述 systemd是Linux操作系统的系统和服务管理器。在启动时作为PID的…

systemd wsl 测试笔记

文章目录 systemd 简介WSL systemdsystemctljournalctlhello serviceSleep 与 Timeout 测试Requires 测试After 测试 systemd 简介 Linux 从关闭到运行, 完整的启动和启动过程有三个主要部分: 硬件启动(Hardware boot): 初始化系统硬件Linux 引导(Linux boot): 加载 Linux 内核…

Linux systemd启动流程

以Ubuntu 18.04.2 LTS为例&#xff0c;列出Systemd启动target中涉及单元(Unit). default.target ( graphical.target by default) graphical.targetRequiresmulti-user.targetWantsdisplay-manager.serviceConflictsrescue.service rescue.targetAftermulti-user.target rescu…

关于 Linux中systemd的一些笔记

写在前面 嗯&#xff0c;准备RHCA&#xff0c;学习整理这部分知识博文内容涉及&#xff1a; systemd简述对于unit的信息的介绍通过systemctl命令控制Service unit的DemoService unit配置文件内容,权值的一些介绍 傍晚时分&#xff0c;你坐在屋檐下&#xff0c;看着天慢慢地黑下…

Linux-Systemd

目录 一、Systemd概述 二、Systemd优势 2.1兼容性 2.2启动速度 2.3systemd 提供按需启动能力 2.4采用 linux 的 cgroups 跟踪和管理进程的生命周期 2.5启动挂载点和自动挂载的管理 2.6实现事务性依赖关系管理 2.7日志服务 2.8 依赖关系 2.9systemd 事务 三、unit(单…

Systemd 简介

一 概述 Linux 服务管理有两种方式service和systemctl。而systemd是Linux系统最新的初始化系统(init)&#xff0c;作用是提高系统的启动速度&#xff0c;尽可能启动较少的进程&#xff0c;尽可能更多进程并发启动&#xff0c;systemd对应的进程管理命令就是systemctl。值得一提…

systemd简介

Systemd 是一个专用于 Linux 操作系统的系统与服务管理器,其目的是要取代Unix时代以来一直在使用的init系统。 systemd概述Systemd 是 Linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度。 systemd框架图 根据 Linux 惯…

Systemd 入门及常用命令

目录 Systemdsystemd架构systemd 系统管理管理系统查看启动耗时查看当前主机的信息 Unit 资源查看当前系统的所有 Unit查看系统状态和单个 Unit 的状态 Unit 管理依赖关系Unit 配置文件查看配置文件的内容 Targettarget&#xff08;Systemd&#xff09; 与 runlevel&#xff08…

systemd 介绍

转自&#xff1a;https://www.linuxidc.com/Linux/2018-03/151291.htm 从 init 系统说起 Linux 操作系统的启动首先从 BIOS 开始&#xff0c;接下来进入 boot loader&#xff0c;由 bootloader 载入内核&#xff0c;进行内核初始化。内核初始化的最后一步就是启动 PID 为 1 的 …

[2020.1.10]systemd介绍

1 systemd基本概念 systemd:a system daemon&#xff0c;相当于以前的init进程&#xff0c;pid1&#xff0c;systemd是1号进程!!! sbin/init --> /lib/systemd/systemd unit: 一个进程,例如lightdm.service job: 一个动作,启动是个job,关闭是个job。开机启动时,systemd…

systemd教程(三)

下来会通过示例来描述不同Service Type值的应用场景。在此之前&#xff0c;强烈建议先阅读前后台进程父子关系和daemon类进程来搞懂进程之间的关系和Daemon类进程的特性。 systemd service&#xff1a;Typeforking 当使用systemd去管理一个长久运行的服务进程时&#xff0c;最…

dpkg打包笔记

dpkg 安装软件 dpkg -i xxx.deb 查看安装目录 dpkg -L xxx 显示版本 dpkg -l xxx 详细信息 dpkg -s xxx 罗列内容 dpkg -c xxxx 卸载软件 dpkg -r xxxx 构建deb包 dpkg -p