基于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>

以上是 基于javassist进行动态编程过程解析 的全部内容, 来源链接: utcz.com/z/357390.html

回到顶部