基于javassist进行动态编程过程解析
作者:玄同太子 发布时间:2021-12-03 07:23:19
标签:java,ssist,动态,编程
今天在研究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


猜你喜欢
- 首先我们看看为什么需要对象复制?为什么需要对象复制如上,是我们平时开发中最常见的三层MVC架构模型,编辑操作时Controller层接收到前
- 如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是Str
- Chart控件可以用来绘制波形图、柱状图、饼图、折线图等,用来进行数据表现是很不错的简单说一下这个控件的使用方法效果图我们首先要加载Char
- Springcloud Config什么是springcloud Config  简单来说,Spring
- 本文为大家分享了java门禁系统面向对象程序设计,供大家参考,具体内容如下下面是对门禁系统的介绍:需求1、某公司安装了电子门,要设计门禁系统
- 对于一个App的UI而言,在流畅性上的改进目标其实就是降低屏幕绘制的延迟,创建流畅和稳定的帧率以避免卡顿。在理想情况下,全部的测量、布局和绘
- 本文实例讲述了C#中const用法。分享给大家供大家参考。具体用法分析如下:const是一个c语言的关键字,它限定一个变量不允许被改变。使用
- 动态数据源在很多具体应用场景的时候,我们需要用到动态数据源的情况,比如多租户的场景,系统登录时需要根据用户信息切换到用户对应的数据库。又比如
- 本文实例讲述了Android编程实现实时监听EditText文本输入的方法。分享给大家供大家参考,具体如下:平时在做Android开发过程中
- 文章描述弱水三千,我只取一瓢饮。一张动图,我只想要其中一帧。如何将一个GIF动态图分割成一帧一帧的图片?其实现在这样的工具随处可见,无论是在
- 业务场景我们知道在使用PageHelper分页插件时,会对执行PageHelper.startPage(pageNum, pageSize)
- 一、Service简介Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有U
- 引言C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就具体看
- Android实现读取NFC卡卡号示例,具体如下:1.权限 <uses-permission android:name=&
- 本篇随笔主要介绍用Java实现简单的装饰器设计模式:先来看一下装饰器设计模式的类图:从图中可以看到,我们可以装饰Component接口的任何
- 谈到多线程就不得不谈到Synchronized,重要性不言而喻,今天主要谈谈Synchronized的实现原理。Synchronizedsy
- 本教程为大家分享了学籍管理系统的具体java代码,供大家参考,具体内容如下1.需求分析 1.1系统功能设计 (1)能够查询学生的基本信息,如
- 前言:回顾上一节服务器配置的内容,我们已经可以自己完成公众号服务器的配置。配置完成之后,我们就可以通过调用的方式,完成对消息管理的处理。当用
- 在Eclipse中创建Android项目,利用之前学过的WebView控件和中国天气网提供的天气数据接口,实现获取指定城市的天气预报。布局文
- Redis 3.X版本引入了集群的新特性,为了保证所开发系统的高可用性项目组决定引用Redis的集群特性。对于Redis数据访问的支持,目前