zoukankan      html  css  js  c++  java
  • 使用javassist进行动态编程

    今天在研究dubbo时,发现一个新的知识点,可以使用javassist包进行动态编程,hibernate也使用该包进行编程。晚上百度了很多资料,将它的特性以代码的形式展现出来。

    package com.zhi.demo;
    
    import java.lang.reflect.Field;
    
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtConstructor;
    import javassist.CtField;
    import javassist.CtMethod;
    import javassist.CtNewConstructor;
    import javassist.CtNewMethod;
    import javassist.Loader;
    import javassist.Modifier;
    import javassist.bytecode.AccessFlag;
    
    /**
     * Javassist动态编程测试
     *
     * @date 2019年03月11日23:00:33
     *
     */
    public class JavassistTest {
        public static void main(String[] args) {
            try {
                test();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static void test() throws Exception {
            System.out.println("-------------------新增类------------------");
            ClassPool pool = ClassPool.getDefault();
            // 创建类
            CtClass ct = pool.makeClass("com.zhi.Person");
            // 让类实现Cloneable接口
            ct.setInterfaces(new CtClass[] { pool.makeInterface("java.lang.Cloneable") });
    
            // 添加一个int类型的共有属性
            CtField fieldId = new CtField(CtClass.intType, "id", ct);
            fieldId.setModifiers(AccessFlag.PUBLIC);
            ct.addField(fieldId);
    
            // 添加一个默认构造器
            CtConstructor constructor1 = CtNewConstructor.make("public Person(){this.id=1;}", ct);
            ct.addConstructor(constructor1);
    
            // 添加方法
            CtMethod helloM = CtNewMethod
                    .make("public void hello(String des){System.out.println("执行hello方法,"+des+",我的id是"+this.id);}", ct);
            ct.addMethod(helloM);
    
            // 将生成的.class文件保存到磁盘
            ct.writeFile();
    
            // 加载目标类,可用ct.toClass()或new Loader(pool).loadClass()
            Class<?> clazz = ct.toClass();
    //        Class<?> clazz = new Loader(pool).loadClass("com.zhi.Person");
    
            // 输出类基本信息
            System.out.println("包名:" + clazz.getPackageName());
            System.out.println("类名:" + clazz.getName());
            System.out.println("简要类名:" + clazz.getSimpleName());
            System.out.println("限定符:" + Modifier.toString(clazz.getModifiers()));
            System.out.println("继承类:" + clazz.getSuperclass().getName());
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("属性名称:" + field.getName() + ",属性类型:" + field.getType() + ",限定符:"
                        + Modifier.toString(field.getModifiers()));
            }
    
            // 构造一个对象,并执行hello方法
            Object ob = clazz.getDeclaredConstructor().newInstance();
            clazz.getMethod("hello", String.class).invoke(ob, "张三");
    
            // 解冻(执行toClass后会自动冻结)
            ct.defrost();
    
            System.out.println("-------------------修改类------------------");
    
            // 添加一个String类型的私有属性
            CtField fieldName = new CtField(pool.get(String.class.getName()), "name", ct);
            fieldName.setModifiers(AccessFlag.PRIVATE);
            ct.addField(fieldName);
    
            // 添加带参的构造函数
            CtConstructor constructor2 = new CtConstructor(new CtClass[] { pool.get(String.class.getName()) }, ct);
            constructor2.setModifiers(Modifier.PUBLIC);
            constructor2.setBody("{this.name=$1;}");
            ct.addConstructor(constructor2);
    
            ct.addMethod(CtNewMethod.make("public void setName(String name){this.name=name;}", ct));
            ct.addMethod(CtNewMethod.make("public String getName(){return this.name;}", ct));
    
            ct.writeFile();
    
            // 加载类,若前面已用ct.toClass()进行加载,则这里不能再用ct.toClass()加载,否则会出错,同一个加载不能2次加载同一个类
            clazz = new Loader(pool).loadClass("com.zhi.Person");
    
            fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("属性名称:" + field.getName() + ",属性类型:" + field.getType() + ",限定符:"
                        + Modifier.toString(field.getModifiers()));
            }
    
            ob = clazz.getDeclaredConstructor(String.class).newInstance("马云");
            System.out.println("执行getName方法得到的值为:" + clazz.getMethod("getName").invoke(ob));
        }
    }

    执行上面代码输出结果为: 

    -------------------新增类------------------
    包名:com.zhi
    类名:com.zhi.Person
    简要类名:Person
    限定符:public
    继承类:java.lang.Object
    属性名称:id,属性类型:int,限定符:public
    执行hello方法,张三,我的id是1
    -------------------修改类------------------
    属性名称:id,属性类型:int,限定符:public
    属性名称:name,属性类型:class java.lang.String,限定符:private
    执行getName方法得到的值为:马云

    说明:

    $0,$1,$2:分别代表this,第一个参数,第二个参数

    $r:方法返回值的类型。

    $_:方法返回值

    依赖包

    <dependency>
        <groupId>org.javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.24.1-GA</version>
    </dependency>
  • 相关阅读:
    css实现文字渐变
    mySql中Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre的问题
    mysql不等于判断时,空值过滤问题
    SpringBoot中maven打包,启动报没有主清单属性
    MySQL插入数据时报错Cause: java.sql.SQLException: #HY000的解决方法
    SpringCloud中Feign服务调用请求方式及参数总结
    linux查看占用端口号的程序及pid
    Ant Design Pro 改变默认启动端口号
    启动jar包并生成日志的linux脚本
    JavaWeb中验证码校验的功能实现
  • 原文地址:https://www.cnblogs.com/zhi-leaf/p/10480913.html
Copyright © 2011-2022 走看看