学习笔记 Javassist的一些应用

首先加先添加依赖项目

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

1.使用情况 创建一个类对象 并使用

大概的使用其实就是用各种的api 程序的意思如下

创建一个新类 

1.创建成员变量(类型,所属的类)  2. 设置访问修饰符 3.  放进类里

2.创建方法 有两种方式

  第一种是   

       1.先创建方法(返回值类型,名称,参数列表)

        2.设置访问修饰符

        3.添加方法体  其实就是之间像是源码一样 写  传入的参数按参数列表的来 $1,$2,$3,...代替

       4.放进类里面

  第二种是

        1.创建方法 直接   “   就java的源码   ”

         2.放入类里面

3.创建构造函数

  如果没有 默认有一个无参构造函数 如果创建了个有参的 放进去了那么 就 不会默认提供无参的

       创建也有两种方式 和创建方法类似

    第一种

        1.先创建方法(参数列表,所属类)

        2.设置访问修饰符

        3.添加方法体  其实就是之间像是源码一样 写  传入的参数按参数列表的来 $1,$2,$3,...代替

       4.放进类里面

     第二种

        1.创建方法 直接   “   就java的源码   ”

         2.放入类里面

至于新创建完这个类 运行后不会出现真正的源码文件以及class  

创建完这个类后通过.toClass()变成java的类对象 因为不可以通过正常的调用 只能通过反射来调用


public class JavassistTests2 {
    public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    // 类库, jvm 中所加载的 class
        ClassPool pool = ClassPool.getDefault();
        // 创建一个新的类, 类名必须为全量类名
        CtClass tClass = pool.makeClass("tests.bytecode.javassist.TC2");
      // 构建新的类的成员变量
        CtField ctFieldNew = new CtField(CtClass.intType,"age",tClass);
      // 设置新的类的成员变量访问修饰符为 public
        ctFieldNew.setModifiers(Modifier.PUBLIC);
      // 将属性添加到类中
        tClass.addField(ctFieldNew);


      //创建新的方法, 参数 1:方法的返回类型,参数 2:名称,参数 3:方法的参数,参数 4:方法所属的类
        CtMethod newMethod1 = new CtMethod(CtClass.intType, "newfun1", new CtClass[]
                {CtClass.intType,CtClass.intType},tClass);
         // 设置方法的访问修饰
        newMethod1.setModifiers(Modifier.PUBLIC);
        // 将新建的方法添加到类中
        tClass.addMethod(newMethod1);
        // 方法体内容代码 $1 代表第一个参数,$2 代表第二个参数
        newMethod1.setBody("return $1 + $2;");


        // 也可以直接创建方法
        CtMethod newMethod2 = CtNewMethod.make("public String newfun2(String str) { return \"newfun2型参\"+str;}", tClass);
         tClass.addMethod(newMethod2);

        // 创建新的构造方法
        CtConstructor tConstructor1= new CtConstructor(new CtClass[]{},tClass);
        tConstructor1.setModifiers(Modifier.PUBLIC);
        tConstructor1.setBody(null);
        tClass.addConstructor(tConstructor1);

        // 也可以直接创建构造函数
        CtConstructor tConstructor2=CtNewConstructor.make("public TC2(int age){this.age=age;}",tClass);
        tClass.addConstructor(tConstructor2);


        
        Class tc2=tClass.toClass();
        System.out.println(tc2);
        
        //有了类对象就可以利用反射来使用这个类了
        //获取类的所有方法 会得到newfun1  newfun2
        Method[] methods=tc2.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        System.out.println();
        System.out.println();
        //获取这个类的属性 会得到age
        Field[] fields = tc2.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        //查看是否有无参构造方法 用反射去调用它无参构造方法创造对象
        //结果tests.bytecode.javassist.TC2@7a46a697
        System.out.println(tc2.newInstance());
        
        //通过反射调用方法
         Method newfun1=tc2.getDeclaredMethod("newfun1",int.class,int.class);
         System.out.println(newfun1.invoke(tc2.newInstance(),1 ,2));
        //通过反射调用方法
        Method newfun2=tc2.getDeclaredMethod("newfun2",String.class);
        System.out.println(  newfun2.invoke(tc2.newInstance(),"你是狗吗" ));

    }


}

下面开始是对已有类的操作  


public class TC1 {
    private int pr;
    public  int pu;


    public TC1(int one) {
    }

    public TC1() {
    }

    public void puvfun(){
        System.out.println(" public void puvfun");
    }
    private void prvfun(){
        System.out.println("private void prvfun");
    }
    public static void pusvfun(){
        System.out.println("public static void pusvfun");
    }
    public  static void prsvfun(){
        System.out.println("public  static void prsvfun");
    }


    public String pusfun(){
        System.out.println(" public void pusfun");
        return " public void pusfun";
    }
    private String prsfun(){
        System.out.println("private void prsfun");
        return "private void prsfun";
    }
    public static String pussfun(){
        System.out.println("public static void pussfun");
        return "public static void pussfun";
    }
    public  static String prssfun(){
        System.out.println("public  static void prssfun");
        return "public  static void prssfun";
    }
    
}

2.使用情况 给已有的一个类添加属性 方法 并使用

创建成员变量 和 创建方法是跟上文一样的

注意这次是        CtClass tClass = pool.get("tests.bytecode.javassist.TC1"); 是获得原有的这个类 不是创建新的类    如果有那个方法名了 不是重载会报错 

   public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    // 类库, jvm 中所加载的 class
        ClassPool pool = ClassPool.getDefault();
        // 创建一个新的类, 类名必须为全量类名
        CtClass tClass = pool.get("tests.bytecode.javassist.TC1");
      // 构建新的类的成员变量
        CtField ctFieldNew = new CtField(CtClass.intType,"age",tClass);
      // 设置新的类的成员变量访问修饰符为 public
        ctFieldNew.setModifiers(Modifier.PUBLIC);
      // 将属性添加到类中
        tClass.addField(ctFieldNew);
        
      //创建新的方法, 参数 1:方法的返回类型,参数 2:名称,参数 3:方法的参数,参数 4:方法所属的类
        CtMethod newMethod1 = new CtMethod(CtClass.intType, "newfun1", new CtClass[]
                {CtClass.intType,CtClass.intType},tClass);
         // 设置方法的访问修饰
        newMethod1.setModifiers(Modifier.PUBLIC);
        // 将新建的方法添加到类中
        tClass.addMethod(newMethod1);
        // 方法体内容代码 $1 代表第一个参数,$2 代表第二个参数
        newMethod1.setBody("return $1 + $2;");
        
         //也可以直接创建方法
        CtMethod newMethod2 = CtNewMethod.make("public String newfun2(String str) { return \"newfun2型参\"+str;}", tClass);
         tClass.addMethod(newMethod2);
         
        // 也可以直接创建构造函数
        CtConstructor tConstructor2=CtNewConstructor.make("public TC1(int age,int a){this.age=age;}",tClass);
        tClass.addConstructor(tConstructor2);
        
        Class tc11=tClass.toClass();
        Class  tc12=TC1.class;
        System.out.println(tc11==tc12);

        //有了类对象就可以利用反射来使用这个类了
        //获取类的所有方法 会得到newfun1  newfun2
        Method[] methods=tc12.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        System.out.println();
        System.out.println();
        //获取这个类的属性 会得到age
        Field[] fields = tc12.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        //查看是否有无参构造方法 用反射去调用它无参构造方法创造对象
        //结果tests.bytecode.javassist.TC2@7a46a697
        System.out.println(tc12.newInstance());

        //通过反射调用方法
         Method newfun1=tc12.getDeclaredMethod("newfun1",int.class,int.class);
         System.out.println(newfun1.invoke(tc12.newInstance(),1 ,2));
        //通过反射调用方法
        Method newfun2=tc12.getDeclaredMethod("newfun2",String.class);
        System.out.println(  newfun2.invoke(tc12.newInstance(),"你是狗吗" ));

    }

结果如下

true
newfun1
newfun2
prvfun
prsfun
puvfun
prsvfun
pusfun
pusvfun
pussfun
prssfun


pr
pu
age
tests.bytecode.javassist.TC1@7a46a697
3
newfun2型参你是狗吗

注意 这时候 修改完的类  和 原有的类 的对象是同一个了 就是

3.使用情况 给已有的一个类的方法进行增强

 public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
         //使用这个javassist 修改的这个类不能先加载到JVM里
       //TC1 tc =new TC1();
        

       //拿到类对象
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("tests.bytecode.javassist.TC1");
        //拿到这个方法对象
        CtMethod puvfunM=cc.getDeclaredMethod("puvfun");
        //对这个方法进行增强
        puvfunM.insertBefore("{System.out.println(\"在前面加强了方法\");}");
        puvfunM.insertAfter("{System.out.println(\"在后面加强了方法\");}");
        //变成Java的类对象
        Class c=cc.toClass();
        //实例化 通过这个类对象反射创建
        TC1 tc1 =(TC1) c.newInstance();
        tc1.puvfun();
        //用普通的创建实例
        TC1 tc2 =new TC1();
        tc2.puvfun();
    }

结果如下

在前面加强了方法
 public void puvfun
在后面加强了方法
在前面加强了方法
 public void puvfun
在后面加强了方法

注意:修改这个类之前这个类不能加载到JVM里 也就是它还没有加载前才可以 否则结果如下

Exception in thread "main" javassist.CannotCompileException: by java.lang.ClassFormatError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "tests/bytecode/javassist/TC1"
	at javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:271)
	at javassist.ClassPool.toClass(ClassPool.java:1240)
	at javassist.ClassPool.toClass(ClassPool.java:1098)
	at javassist.ClassPool.toClass(ClassPool.java:1056)
	at javassist.CtClass.toClass(CtClass.java:1298)
	at tests.bytecode.javassist.JavassistTests.main(JavassistTests.java:18)
Caused by: java.lang.ClassFormatError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "tests/bytecode/javassist/TC1"
	at javassist.util.proxy.DefineClassHelper$Java7.defineClass(DefineClassHelper.java:182)
	at javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:260)
	... 5 more

总结:

 目前的学习情况来看 并不能做热更新=。=

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值