javassist 使用笔记
javassist
Javassist 是一个开源的分析、编辑和创建Java字节码的类库。其主要的优点,在于简单,而且快速。直接使用 java 编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
- ClassPool:一个基于 Hashtable 实现的 CtClass 对象容器,其中键是类名称,值是表示该类的 CtClass 对象。
- CtClass:CtClass 表示类,一个 CtClass (编译时类)对象可以处理一个 class 文件,这些 CtClass 对象可以从 ClassPool 获得。
- CtMethods:表示类中的方法。
- CtFields :表示类中的字段。
ClassPool
获取 classpool 对象
// 获取 ClassPool 对象,使用系统默认类路径
ClassPool pool = new ClassPool(true);
// 效果与 new ClassPool(true) 一致
ClassPool pool1 = ClassPool.getDefault();
获取类
// 通过类名获取 CtClass,未找到会抛出异常
CtClass ctClass = pool.get("org.test.demo.DemoService");
// 通过类名获取 CtClass,未找到返回 null,不会抛出异常
CtClass ctClass1 = pool.getOrNull("org.test.demo.DemoService");
创建类
// 复制一个类,创建一个新类
CtClass ctClass2 = pool.getAndRename("org.test.demo.DemoService", "org.test.demo.DemoCopyService");
// 通过类名,创建一个新类
CtClass ctClass3 = pool.makeClass("org.test.demo.NewDemoService");
// 通过文件流,创建一个新类,注意文件必须是编译后的 class 文件,不是源代码文件。
CtClass ctClass4 = pool.makeClass(new FileInputStream(new File("./customize/DemoBeforeHandler.class")));
添加类搜索路径
// 将类搜索路径插入到搜索路径之前
pool.insertClassPath(new ClassClassPath(this.getClass()));
// 将类搜索路径添加到搜索路径之后
pool.appendClassPath(new ClassClassPath(this.getClass()));
// 将一个目录作为类搜索路径
pool.insertClassPath("/usr/local/javalib");
CtClass
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("javassist.test02.Person");
//类名
String name = ctClass.getName();
//包名
String packageName = ctClass.getPackageName();
//父类
CtClass superclass = ctClass.getSuperclass();
//接口
CtClass[] interfaces = ctClass.getInterfaces();
System.out.println(name);
System.out.println(packageName);
System.out.println(superclass.getName());
System.out.println(interfaces[0].getName());
}
CtMethod
// 在方法体前插入代码块
ctMethod.insertBefore("");
// 在方法体后插入代码块
ctMethod.insertAfter("");
// 在某行 字节码 后插入代码块
ctMethod.insertAt(10, "");
// 添加参数
ctMethod.addParameter(CtClass);
// 设置方法名
ctMethod.setName("newName");
// 设置方法体
ctMethod.setBody("System.out.println(123);");
创建新类和调用
package javassist.test;
import javassist.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* Created by ssr on 2020/9/15.
*/
public class JavassistTest01 {
public static void main(String[] args) throws Exception{
// 获取 ClassPool 对象,使用系统默认类路径
ClassPool classPool = ClassPool.getDefault();
// 创建一个空类
CtClass ctClass = classPool.makeClass("Test");
// 新增 String 类型字段 name
CtField name = new CtField(classPool.get(String.class.getName()), "name", ctClass);
// 新增 int 类型字段 age
CtField age = new CtField(classPool.get(int.class.getName()), "age", ctClass);
// 设置修饰符 private
name.setModifiers(Modifier.PRIVATE);
age.setModifiers(Modifier.PRIVATE);
//添加到类里
ctClass.addField(name);
ctClass.addField(age);
// 无参构造方法
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{},ctClass);
// 有参构造方法
CtConstructor ctConstructor1 = new CtConstructor(new CtClass[]{classPool.get(String.class.getName()), CtClass.intType}, ctClass);
// 方法体
ctConstructor.setBody("{name=\"test\";age=12;}");
// 方法体 $0 代表this $1 $2 方法参数 name age
ctConstructor1.setBody("{$0.name = $1;$0.age = $2;}");
ctClass.addConstructor(ctConstructor);
ctClass.addConstructor(ctConstructor1);
//创建 getter setter 方法
CtMethod setName = CtNewMethod.setter("setName", name);
CtMethod getName = CtNewMethod.getter("getName", name);
CtMethod getAge = CtNewMethod.getter("getAge", age);
CtMethod setAge = CtNewMethod.setter("setAge", age);
ctClass.addMethod(setName);
ctClass.addMethod(getName);
ctClass.addMethod(getAge);
ctClass.addMethod(setAge);
//新增方法
CtMethod printName = new CtMethod(new CtClass(String.class.getName()) {
@Override
public String toString() {
return super.toString();
}
}, "printInfo", new CtClass[]{}, ctClass);
// 设置方法修饰符 public
printName.setModifiers(Modifier.PUBLIC);
// 设置方法体
printName.setBody("{return \"my name is \"+name+\",\" + \"age is \"+age;}");
ctClass.addMethod(printName);
// 写入文件
ctClass.writeFile("D:\\漏洞分析\\Commons Collections 3.1\\src\\main\\java\\javassist\\test");
//将创建的ctClass加载至当前线程的上下文类加载器中
Class clz = ctClass.toClass();
//反射调用
Constructor declaredConstructor = clz.getDeclaredConstructor(String.class, int.class);
Object obj = declaredConstructor.newInstance("liangzi", 100);
Method printInfo = clz.getMethod("printInfo");
System.out.println(printInfo.invoke(obj));
}
}
修改类
- 原始类
package javassist.test03;
public class Test {
private void info(String name){
System.out.println(name);
}
}
- 修改
package javassist.test03;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import java.lang.reflect.Method;
public class JavassistTest01 {
public static void main(String[] args) throws Exception{
ClassPool pool = ClassPool.getDefault();
// 通过类名获取 CtClass,未找到会抛出异常
CtClass ctClass = pool.get("javassist.test03.Test");
// 获取类中的info方法
CtMethod info = ctClass.getDeclaredMethod("info");
// 修改info方法修饰符为 public
info.setModifiers(Modifier.PUBLIC);
// 方法开头添加语句
info.insertBefore("{System.out.println(\"000\");}");
// 方法结尾添加语句
info.insertAfter("{System.out.println(\"111\");}");
Class cls = ctClass.toClass();
Object o = cls.newInstance();
Method info1 = cls.getMethod("info", String.class);
info1.invoke(o,"bbb");
}
}
javassist 使用笔记的更多相关文章
- 8.5(java学习笔记)8.5 字节码操作(javassist)
一.javassist javassist让我们操作字节码更加简单,它是一个类库,允许我们修改字节码.它允许java程序动态的创建.修改类. javassist提供了两个层次的API,基于源码级别的和 ...
- Flex4+Spring3+Hibernate3+BlazeDS整合笔记
普通Java Web工程流行使用ssh框架,而当前台使用Flex制作的时候,后台就不需要用Struts了,通过使用BlazeDS远程方法调用即可. 首先,新建Java Web工程,然后添加Flex项目 ...
- 《Thinking In Java》阅读笔记
<Thinking In Java>阅读笔记 前四章:对象导论. 一切都是对象. 操作符. 控制执行流程 public在一个文件中只能有一个,可以是一个类class或者一个接口interf ...
- MyBatis学习笔记(三) Configuration类
一.初探Configuration类 我们先来看一下MyBatis的XML配置文件的结构,(摘自mybatis.org) 下面这个是Configuration类的部分变量 一点不一样是不是??? 其实 ...
- Javassist 字节码 简介 案例 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Javassist 字节码 语法 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Dubbo -- 系统学习 笔记 -- 配置参考手册
Dubbo -- 系统学习 笔记 -- 目录 配置参考手册 <dubbo:service/> <dubbo:reference/> <dubbo:protocol/> ...
- Dubbo -- 系统学习 笔记 -- 依赖
Dubbo -- 系统学习 笔记 -- 目录 依赖 必需依赖 缺省依赖 可选依赖 依赖 必需依赖 JDK1.5+ 理论上Dubbo可以只依赖JDK,不依赖于任何三方库运行,只需配置使用JDK相关实现策 ...
- [置顶]
Android AOP 实践笔记
本文同步自wing的地方酒馆 最近博客更新越来越慢了,有两方面原因: 1.没啥好写的. 2.应该沉下心好好沉淀自己,积累一些东西,博客写的太频繁有"刷博客"之嫌,还容易浮躁. 浮躁 ...
随机推荐
- K8S系列第九篇(持久化存储,emptyDir、hostPath、PV/PVC)
更多k8s内容,请关注威信公众好:新猿技术生态圈 一.数据持久化 Pod是由容器组成的,而容器宕机或停止之后,数据就随之丢了,那么这也就意味着我们在做Kubernetes集群的时候就不得不考虑存储的问 ...
- null是对象吗?
null是基本数据类型但是typeof null为object,这是因为在js存储中对象是以000开头的,而null是一个空,相当于全0,所以typeof null也是object 在js中,变量由类 ...
- i春秋“百度杯”CTF比赛 十月场-Vld(单引号逃逸+报错注入)
题目源代码给出了提示index.php.txt,打开拿到了一段看不太懂得东西. 图片标注的有flag1,flag2,flag3,同时还有三段字符,然后还出现了_GET,脑洞一一点想到访问 ?flag1 ...
- RHCSA_DAY07
echo $PATH 用户账号管理 用户账号的作用:用户账号可用来登录系统,可以实现访问控制 用户模板目录:/etc/skel/ [root@localhost ~]# ls -a /etc/skel ...
- Linux服务器下JVM堆栈信息dump及问题排查
#dump 方法栈信息 jstack $pid > /home/$pid/jstack.txt #dump jvm内存使用情况 jmap -heap $pid > /home/$pid/j ...
- Linux 开机关机在线求助与指令输入
由于那本书版本稍稍有点早,我就跳过学习第二章第三章了(分别是主机规划和虚拟机安装)下图为在自己电脑上安装好的redhat7 4.1 我们来登入 其中第一行是Linux发行商和发行版本(欸,我的这个怎么 ...
- Typora+Markdown便捷发布blog
参考文章:https://www.cnblogs.com/Heroge/p/12459762.html 需要下载Typora和dotnet Typora下载链接:https://www.typora. ...
- [1.6W字]浏览器跨域请求的原理, 以及解决方法(可以纯前端实现) #flight.Archives011
Title/ 浏览器跨域(CrossOrigin)请求的原理, 以及解决方案详细指南 #flight.Archives011 序: 最近看到又有一波新的创作活动了, 官方给出的话题中有一个" ...
- Asp.NetCore 中Aop的应用
前言 其实好多项目中,做一些数据拦截.数据缓存都有Aop的概念,只是实现方式不一样:之前大家可能都会利用过滤器来实现Aop的功能,如果是Asp.NetCore的话,也可能会使用中间件: 而这种实现方式 ...
- C# 异步锁 await async锁,lock,Monitor,SemaphoreSlim
异步方法内无法使用Monitor 和lock 所以只能用System.Threading.SemaphoreSlim了 //Semaphore (int initialCount, int maxim ...