java动态生成类javassist

简述

Javassist(Java Programming Assistant)是一个 操作Java 字节码的类库,主要用于在运行时或编译时修改 Java 类的字节码

它提供了相对简单的 API,让开发者可以动态地创建、修改和加载 Java 类 , 从而实现诸如动态代理、AOP(面向切面编程)、代码生成等高级功能。

API学习

1)ClassPool

作用:ClassPool 作为一个类管理器,用于动态加载、操作 (对类的字段、方法进行增删改查操作) 和生成 Java 类的字节码。        

相关API

ClassPool.getDefault()

介绍:获取默认类池,采用单例模式,每次获取的类池都是同一个

makeClass(String className)、

    makeInterface(String className)、

    makeAnnotation(String className)

介绍:在内存中创建类、接口、注解的字节码,返回的都是CtClass对象,此时还并未将类装载到JVM

get(String className)

    getCtClass(String className)

介绍:获取内存中类的字节码对象

2)CtClass

作用:封装类的字节码信息(这里的类是统称,代表Java中的类、接口、注解等)

相关API

void addField(CtField f)、

   void addMethod(CtMethod m)、

   void addConstructor(CtConstructor c)

添加字段、方法、构造器

void addInterface(CtClass ctInterface)、

    void setInterfaces(CtClass[] list)

继承一个接口、多个接口

void setSuperclass(CtClass clazz)

指定父类

Class<?> toClass()

将字节码类装载到JVM,并返回Class对象

void writeFile(String directoryName)

将类保存到文件

应用

导入maven依赖

<!--  javassist  -->
<dependency>
   <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.29.2-GA</version>
</dependency>
<!--  单元测试  -->
<dependency>
   <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

创建如下的一个接口,一个类

package com.xxx;
​
public interface FunctionInterface {
    void print(Object o);
}
package com.xxx;
​
public class FunctionImpl implements FunctionInterface{
    public void print(Object o) {
        System.out.println(o);
    }
}

利用javassist生成类代码如下:

① 在内存中创建接口FunctionInterface的字节码,并加载到JVM

 Class<?> makeFunctionInterface() throws Exception {
     //  1.获取默认类池
     ClassPool classPool = ClassPool.getDefault();
     //  2.创建接口的内存字节码
     CtClass functionInterfaceCt = classPool.makeInterface("com.xxx.FunctionInterface");
     //  3.在内存中添加方法声明
     //      3.1创建方法声明,并指定所属
     CtMethod printMethodDeclare = CtMethod.make("void print(Object o);", functionInterfaceCt);
     //      3.2添加方法声明
     functionInterfaceCt.addMethod(printMethodDeclare);
     //  4.将接口装载到虚拟机
     Class<?> functionInterface = functionInterfaceCt.toClass();
     return functionInterface;
 }

② 在内存中创建类FunctionImpl的字节码,并加载到JVM

Class<?> makeFunctionImpl() throws Exception {
     //  1.获取默认类池
    ClassPool classPool = ClassPool.getDefault();
    //  2.创建类的内存字节码
    CtClass functionImplCt = classPool.makeClass("com.xxx.FunctionImpl");
    //  3.继承接口
    functionImplCt.addInterface(classPool.getCtClass("com.xxx.FunctionInterface"));
    //  4.在内存中添加方法实现
    //      4.1创建方法实现,并指定所属
    CtMethod printMethodImpl = CtMethod.make("public void print(Object o){System.out.println(o);}", functionImplCt);
    //      4.2添加方法实现
    functionImplCt.addMethod(printMethodImpl);
    //  5.将类装载到虚拟机
    Class<?> functionImpl = functionImplCt.toClass();
    return functionImpl;
}

③ 通过反射测试对象的生成以及print方法的调用

void testNewObject() throws Exception {
     //  1.反射创建对象
    Object functionImplObject = Class.forName("com.xxx.FunctionImpl").newInstance();
    //  2.获取print方法
    Method printMethod = functionImplObject.getClass().getMethod("print", Object.class);
    //  3.执行方法
    printMethod.invoke(functionImplObject, "hello, javassist!");
}

问题解决

java.lang.reflect.InaccessibleObjectException:如果JDK版本>8,那么添加如下JVM参数和环境变量参数:

JVM参数:--add-opens java.base/java.lang=ALL-UNNAMED

环境变量:--add-opens java.base/sun.net.util=ALL-UNNAMED

  • 74
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值