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

作者:玄同太子 时间:2021-12-03 07:23:19 

今天在研究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>

来源:https://www.cnblogs.com/zhi-leaf/p/10480913.html

标签:java,ssist,动态,编程
0
投稿

猜你喜欢

  • 解决spring boot启动扫描不到自定义注解的问题

    2023-10-29 14:31:48
  • java 读取excel文件转换成json格式的实例代码

    2023-09-11 13:07:28
  • Java 设计模式之责任链模式及异步责任链详解

    2021-08-08 19:14:23
  • Java中对于双属性枚举的使用案例

    2023-07-20 15:00:09
  • java并发编程_线程池的使用方法(详解)

    2023-03-29 22:23:00
  • javax.persistence中@Column定义字段类型方式

    2021-12-03 21:21:44
  • Java 通过AQS实现数据组织

    2023-04-05 22:19:29
  • 基于Java汇总Spock框架Mock静态资源经验

    2023-11-25 04:42:29
  • spring data jpa使用详解(推荐)

    2022-06-19 05:22:17
  • Flutter 实现下拉刷新上拉加载的示例代码

    2023-08-18 21:31:16
  • springboot使用log4j2异步日志提升性能的实现方式

    2021-05-31 16:54:55
  • Java 用Prometheus搭建实时监控系统过程详解

    2023-09-06 12:07:40
  • C语言时间函数之strftime()详解

    2023-06-26 02:42:32
  • java基础之Object类

    2022-11-17 21:20:10
  • Kotlin之在Gradle中无参(no-arg)编译器插件的使用详解

    2023-07-31 19:11:43
  • SpringCloud分布式链路追踪组件Sleuth配置详解

    2023-11-28 23:58:42
  • SpringBoot中JPA实现Sort排序的三种方式小结

    2022-02-12 23:35:12
  • java9版本特性资源自动关闭的语法增强

    2023-10-30 23:35:24
  • Java利用Swagger2自动生成对外接口的文档

    2023-03-31 03:22:38
  • spring如何实现两个xml配置文件间的互调

    2021-06-07 20:50:15
  • asp之家 软件编程 m.aspxhome.com