APM - Javassist 入门 生成一个简单类
程序员文章站
2022-06-18 11:17:24
...
官网
http://www.javassist.org/tutorial/tutorial.html
概述
Javassist是一个开源的分析、编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码。
相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
Javassist简单易用, 快速。
Javassist作用
- 运行时监控插桩埋点
- AOP动态代理实现(性能上比Cglib生成的要慢)
- 获取访问类结构信息:如获取参数名称信息
常用API
类 | 说明 |
---|---|
ClassPool | Javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类, 与 JVM ClassLoader相似 |
CtClass | CtClass提供了类的操作,如在类中动态添加新字段、方法和构造函数、以及改变类、父类和接口的方法。 |
CtMethod | 类中的方法,通过它可以给类创建新的方法,还可以修改返回类型,访问修饰符等, 甚至还可以修改方法体内容代码 |
CtConstructor | 构造函数 |
CtField | 类的属性,通过它可以给类创建新的属性,还可以修改已有的属性的类型,访问修饰符等 |
Javassist 语法
项目 | Value |
---|---|
$0, $1, $2, … | this and actual parameters |
$args | An array of parameters. The type of $args is Object[]. |
$$ | All actual parameters.For example, 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. |
Javassist使用流程
Demo
依赖
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
import javassist.*;
/**
* 使用Javassist 构建 一个新的类 并执行
*/
public class FirstJavasisit {
public static void main(String[] args) throws CannotCompileException,
NotFoundException, InstantiationException, IllegalAccessException {
ClassPool pool = new ClassPool(true);
// 插入类路径,通过类路径去搜索我们要的类
pool.insertClassPath(new LoaderClassPath(FirstJavasisit.class.getClassLoader()));
// 构建一个新的CtClass对象
CtClass targetClass = pool.makeClass("com.artisan.Hello");
// 实现一个接口
targetClass.addInterface(pool.get(IHello.class.getName()));
// 获取返回类型
CtClass returnType = pool.get(void.class.getName());
// 方法名称
String mname = "sayHello";
// 方法参数
CtClass[] parameters = new CtClass[]{pool.get(String.class.getName())};
// 实例化方法
CtMethod method = new CtMethod(returnType, mname, parameters, targetClass);
// 方法中的源码
String src = "{"
+ "System.out.println($1);"
+ "}";
// 设置src到方法中
method.setBody(src);
// 添加方法
targetClass.addMethod(method);
// 装在到当前的ClassLoader中
Class cla = targetClass.toClass();
// 实例化
IHello hello = (IHello) cla.newInstance();
// 方法调用
hello.sayHello("artisan");
}
/**
* 接口不是必须的,只是为了方便演示,少写点反射代码
*/
public interface IHello {
void sayHello(String name);
}
}
注意事项
- 所引用的类型,必须通过ClassPool获取后才可以使用
- 代码块中所用到的引用类型,使用时必须写全量类名
- 代码块内容写错了,只有在运行时才报错
- javassist只接受单个语句或用大括号括起来的语句块
- 动态修改的类,必须在修改之前,jvm中不存在这个类的实例对象。修改方法的实现必须在修改的类加载之前进行
参考
https://baijiahao.baidu.com/s?id=1660843613132087355&wfr=spider&for=pc
https://www.cnblogs.com/scy251147/p/11100961.html
https://blog.csdn.net/21aspnet/article/details/81671777
https://www.cnblogs.com/rickiyang/p/11336268.html
上一篇: 反射