zoukankan      html  css  js  c++  java
  • 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");
        }
    }
    

  • 相关阅读:
    package相关知识
    【算法设计与分析】5个数7次比较排序的算法
    Android下的应用编程——用HTTP协议实现文件上传功能
    5个数通过7次比较排序的方法
    数据库范式(1NF、2NF、3NF、BCNF)
    HttpDownloader2011年09月20日 写好用于下载的类 并且封装好
    POJ 1692 DP
    POJ 1682 多重DP
    TYVJ 1744 逆序对数(加强版)
    POJ 2151 概率DP
  • 原文地址:https://www.cnblogs.com/depycode/p/13676295.html
Copyright © 2011-2022 走看看