网上copy~:
Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件。Javassist使用户不必关心字节码相关的规范也是可以编辑类文件的。
1.ClassPool
ClassPool:一个基于哈希表(Hashtable)实现的CtClass对象容器,其中键名是类名称,值是表示该类的CtClass对象
常用方法
static ClassPool getDefault()
返回默认的类池。
ClassPath insertClassPath(java.lang.String pathname)
在搜索路径的开头插入目录或jar(或zip)文件。
ClassPath insertClassPath(ClassPath cp)
ClassPath在搜索路径的开头插入一个对象。
java.lang.ClassLoader getClassLoader()
获取类加载器toClass(),getAnnotations()在 CtClass等
CtClass get(java.lang.String classname)
从源中读取类文件,并返回对CtClass 表示该类文件的对象的引用。
ClassPath appendClassPath(ClassPath cp)
将ClassPath对象附加到搜索路径的末尾。
CtClass makeClass(java.lang.String classname)
创建一个新的public类
2.CtClass
CtClass表示类,一个CtClass(编译时类)对象可以处理一个class文件,这些CtClass对象可以从ClassPoold的一些方法获得。
void setSuperclass(CtClass clazz)
更改超类,除非此对象表示接口。
java.lang.Class> toClass(java.lang.invoke.MethodHandles.Lookup lookup)
将此类转换为java.lang.Class对象。
byte[] toBytecode()
将该类转换为类文件。
void writeFile()
将由此CtClass 对象表示的类文件写入当前目录。
void writeFile(java.lang.String directoryName)
将由此CtClass 对象表示的类文件写入本地磁盘。
CtConstructor makeClassInitializer()
制作一个空的类初始化程序(静态构造函数)。
3.CtMethod
CtMethod:表示类中的方法。
void setBody(java.lang.String src)
设置构造函数主体。
void setBody(CtConstructor src, ClassMap map)
从另一个构造函数复制一个构造函数主体。
CtMethod toMethod(java.lang.String name, CtClass declaring)
复制此构造函数并将其转换为方法。
4.CtConstructor
CtConstructor的实例表示一个构造函数。它可能代表一个静态构造函数(类初始化器)。
具体不做过多介绍,参考连接
https://blog.csdn.net/weixin_39876592/article/details/111256182
1.创建类玩法
ClassPool cp = ClassPool.getDefault();
CtClass ctClass = cp.makeClass("org.example.ClassLoaders.Met32");
ctClass.writeFile("src/main/java");
2.向存在的类植入代码
在下面代码中,本人首先准备了一个现有的类User,并给User中的say方法植入代码
User:
public class User {
public void say(){
System.out.println("User say");
}
}
ClassPool cp = ClassPool.getDefault();
CtClass ct2 = cp.get("org.example.ClassLoaders.User");
CtMethod ctMethod = ct2.getDeclaredMethod("say");
ctMethod.insertBefore("Runtime.getRuntime().exec(\"calc\");");
Class clazz = ct2.toClass();
User user = (User) clazz.newInstance();
user.say();
可以看见User中的say方法,成功被植入,这就类似于aop
3. 实现set和get方法
ClassPool cp = ClassPool.getDefault();
CtClass ctClass = cp.makeClass("org.example.ClassLoaders.Hello");
CtField ctField = new CtField(CtClass.intType,"value",ctClass);
ctField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ctField);
CtMethod ctMethod = new CtMethod(CtClass.voidType,"setValue",new CtClass[]{CtClass.intType},ctClass);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("this.value = $1;");
ctMethod.insertBefore("System.out.println(\"Before....\");");
ctMethod.insertAfter("System.out.println(\"After....\");");
ctClass.addMethod(ctMethod);
CtMethod getValue = new CtMethod(CtClass.intType,"getValue",new CtClass[]{},ctClass);
getValue.setModifiers(Modifier.PUBLIC);
getValue.setBody("return this.value;");
ctClass.addMethod(getValue);
4.toClass and toBytecode
其实比较通用的还是获取类的byte或者获取class。
ClassPool cp = ClassPool.getDefault();
CtClass ctClass = cp.get("org.example.ClassLoaders.User");
byte[] bytes = ctClass.toBytecode();//获取byte
String str = Arrays.toString(bytes);
System.out.println(str);
Class cls = ctClass.toClass();//获取class
User user = (User) cls.newInstance();
user.say();
下方扫一下扫,即可关注