基于javassist进行动态编程过程解析

 更新时间:2020年05月14日 10:00:38   作者:玄同太子  
这篇文章主要介绍了基于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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot2.动态@Value的实现方式

    SpringBoot2.动态@Value的实现方式

    这篇文章主要介绍了SpringBoot2.动态@Value的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Java常见数据结构面试题(带答案)

    Java常见数据结构面试题(带答案)

    这篇文章主要介绍了Java常见数据结构面试题,带有答案及解释,希望对广大的程序爱好者有所帮助,同时祝大家有一个好成绩,需要的朋友可以参考下。
    2017-09-09
  • Java基础之详细总结五种常用运算符

    Java基础之详细总结五种常用运算符

    在通常代码逻辑处理中,我们常常都会使用到运算符,今天我们就详细了解一下运算符的使用以及分类.运算符是对常量或者变量进行操作的符号,它分为算术运算符,赋值运算符,比较运算符,逻辑运算符以及位运算符.需要的朋友可以参考下
    2021-05-05
  • Java中的== 和equals()方法详解与实例

    Java中的== 和equals()方法详解与实例

    本篇文章介绍了,在java中"==" 与equals方法的使用及其实例,需要的朋友可以参考下
    2017-04-04
  • 详解基于IDEA2020.1的JAVA代码提示插件开发例子

    详解基于IDEA2020.1的JAVA代码提示插件开发例子

    这篇文章主要介绍了详解基于IDEA2020.1的JAVA代码提示插件开发例子,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java Fork/Join框架

    Java Fork/Join框架

    Fork/Join框架是Java7中新增的一项特性,也是Java7平台的其中一项主要改进。下面我们就来简单探讨下Java的Fork/Join框架
    2016-09-09
  • SpringBoot没有读取到application.yml问题及解决

    SpringBoot没有读取到application.yml问题及解决

    这篇文章主要介绍了SpringBoot没有读取到application.yml问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Java并发工具类Exchanger的相关知识总结

    Java并发工具类Exchanger的相关知识总结

    今天给大家带来的文章是Java工具类Exchanger的相关知识总结,文中有非常详细的介绍及代码示例,对正在学习java的小伙伴们很有帮助,需要的朋友可以参考下
    2021-06-06
  • 探究实现Aware接口的原理及使用

    探究实现Aware接口的原理及使用

    这篇文章主要为大家介绍了探究实现Aware接口的原理及使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • SpringBoot 多任务并行+线程池处理的实现

    SpringBoot 多任务并行+线程池处理的实现

    这篇文章主要介绍了SpringBoot 多任务并行+线程池处理的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04

最新评论