首页 > 编程语言 >javassist动态生成类

javassist动态生成类

时间:2023-06-03 13:33:03浏览次数:38  
标签:methodCode 生成 powernode ctClass 动态 com append javassist

1. 使⽤javassist⽣成类   58

来⾃百度百科:Javassist是⼀个开源的分析、编辑和创建Java字节码的类库。是由东京⼯业⼤学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加⼊了开放源代码JBoss 应⽤服务器项⽬,通过使⽤Javassist对字节码操作为JBoss实现动态"AOP"框架。

2. Javassist的使⽤    59 

我们要使⽤javassist,⾸先要引⼊它的依赖

<dependency>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 <version>3.29.1-GA</version>
</dependency>

3. 案例演示   59

3.1 注意高于jdk8版本的   59

运⾏要注意:加两个参数,要不然会有异常。 

--add-opens java.base/java.lang=ALL-UNNAMED 

--add-opens java.base/sun.net.util=ALL-UNNAMED

javassist动态生成类_System

3.2 案例演示javassist生成类 59

代码在com.powernode.bank.dao.AccountDao

JavassistTest中的testGenerateFirstClass方法
//案例演示javassist生成类 59
    @Test
    public void testGenerateFirstClass() throws Exception{
        // 获取类池,这个类池就是用来给我生成class的
        ClassPool pool = ClassPool.getDefault();
        // 制造类(需要告诉javassist,类名是啥)
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类class
        ctClass.toClass();


        // 类加载到JVM当中,返回AccountDaoImpl类的字节码
        Class clazz = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 创建对象
        Object obj = clazz.newInstance();
        // 获取AccountDaoImpl中的insert方法
        Method insertMethod = clazz.getDeclaredMethod("insert");
        // 调用方法insert
        insertMethod.invoke(obj);
    }

javassist动态生成类_java_02

3.3 演示javassist实现接口  60

com.powernode.bank.dao

AccountDao
package com.powernode.bank.dao;

//这是一个接口看看javassist能不能实现  60
public interface AccountDao {
    void delete();
}

代码在com.powernode.bank.dao.AccountDao

JavassistTest中的testGenerateImpl方法
//演示javassist实现接口  60
    @Test
    public void testGenerateImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 添加接口到类中
        ctClass.addInterface(ctInterface); // AccountDaoImpl implements AccountDao
        // 实现接口中的方法
        // 制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类,同时将生成的类加载到JVM当中。
        Class clazz = ctClass.toClass();
        // 创建对象这里进行了强转为AccountDao类型了,所以创建出来的对象可以直接调方法了
        AccountDao accountDao = (AccountDao)clazz.newInstance();
        accountDao.delete();
    }

javassist动态生成类_System_03

3.4 演示javassist动态实现接口类  61

代码在com.powernode.bank.dao.AccountDao

JavassistTest中的testGenerateAccountDaoImpl方法
//演示javassist动态实现接口类  61
    @Test
    public void testGenerateAccountDaoImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        // 获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            // method是接口中的抽象方法
            // 把method抽象方法给实现了。
            try {
                // public void delete(){}
                // public int update(String actno, Double balance){}
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public "); // 追加修饰符列表
                methodCode.append(method.getReturnType().getName()); // 追加返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName()); //追加方法名
                methodCode.append("(");
                // 拼接参数 String actno, Double balance
                Class[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append("){System.out.println(11111); ");
                // 动态的添加return语句
                String returnTypeSimpleName = method.getReturnType().getSimpleName();
                if ("void".equals(returnTypeSimpleName)) {

                }else if("int".equals(returnTypeSimpleName)){
                    methodCode.append("return 1;");
                }else if("String".equals(returnTypeSimpleName)){
                    methodCode.append("return \"hello\";");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                //给ctClass制造方法
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                //将方法添加到类中 
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });

        // 在内存中生成class,并且加载到JVM当中
        Class clazz = ctClass.toClass();
        // 创建对象
        AccountDao accountDao = (AccountDao) clazz.newInstance();
        // 调用方法
        accountDao.insert("aaaaa");
        accountDao.delete();
        accountDao.update("aaaa", 1000.0);
        accountDao.selectByActno("aaaa");
    }

4. 代码   58-61

代码在com.powernode.javassist

JavassistTest

package com.powernode.javassist;

import com.powernode.bank.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Method;
import java.util.Arrays;

//案例演示javassist  59
public class JavassistTest {

    //演示javassist动态实现接口类  61
    @Test
    public void testGenerateAccountDaoImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        // 获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            // method是接口中的抽象方法
            // 把method抽象方法给实现了。
            try {
                // public void delete(){}
                // public int update(String actno, Double balance){}
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public "); // 追加修饰符列表
                methodCode.append(method.getReturnType().getName()); // 追加返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName()); //追加方法名
                methodCode.append("(");
                // 拼接参数 String actno, Double balance
                Class[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append("){System.out.println(11111); ");
                // 动态的添加return语句
                String returnTypeSimpleName = method.getReturnType().getSimpleName();
                if ("void".equals(returnTypeSimpleName)) {

                }else if("int".equals(returnTypeSimpleName)){
                    methodCode.append("return 1;");
                }else if("String".equals(returnTypeSimpleName)){
                    methodCode.append("return \"hello\";");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                //给ctClass制造方法
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                //将方法添加到类中
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });

        // 在内存中生成class,并且加载到JVM当中
        Class clazz = ctClass.toClass();
        // 创建对象
        AccountDao accountDao = (AccountDao) clazz.newInstance();
        // 调用方法
        accountDao.insert("aaaaa");
        accountDao.delete();
        accountDao.update("aaaa", 1000.0);
        accountDao.selectByActno("aaaa");
    }



    //演示javassist实现接口  60
    @Test
    public void testGenerateImpl() throws Exception{
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        // 添加接口到类中
        ctClass.addInterface(ctInterface); // AccountDaoImpl implements AccountDao
        // 实现接口中的方法
        // 制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类,同时将生成的类加载到JVM当中。
        Class clazz = ctClass.toClass();
        // 创建对象这里进行了强转为AccountDao类型了,所以创建出来的对象可以直接调方法了
        AccountDao accountDao = (AccountDao)clazz.newInstance();
        accountDao.delete();
    }


    //案例演示javassist生成类 59
    @Test
    public void testGenerateFirstClass() throws Exception{
        // 获取类池,这个类池就是用来给我生成class的
        ClassPool pool = ClassPool.getDefault();
        // 制造类(需要告诉javassist,类名是啥)
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        // 将方法添加到类中
        ctClass.addMethod(ctMethod);
        // 在内存中生成类class
        ctClass.toClass();


        // 类加载到JVM当中,返回AccountDaoImpl类的字节码
        Class clazz = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
        // 创建对象
        Object obj = clazz.newInstance();
        // 获取AccountDaoImpl中的insert方法
        Method insertMethod = clazz.getDeclaredMethod("insert");
        // 调用方法insert
        insertMethod.invoke(obj);
    }
}

com.powernode.bank.dao

接口AccountDao

package com.powernode.bank.dao;

//这是一个接口看看javassist能不能实现  60
public interface AccountDao {
    void delete();
    int insert(String actno);
    int update(String actno, Double balance);
    String selectByActno(String actno);
}

配置文件pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>course11</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <dependencies>
        <!--javassist依赖-->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.29.1-GA</version>
        </dependency>
        <!--junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <!--    编译代码使用的jdk版本-->
        <maven.compiler.source>1.8</maven.compiler.source>
        <!--    运行程序使用的jdk版本-->
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>


</project>

标签:methodCode,生成,powernode,ctClass,动态,com,append,javassist
From: https://blog.51cto.com/u_15784725/6407826

相关文章

  • js 动态添加样式
    //添加css脚本exportconstloadStyle=url=>{constlink=document.createElement('link');link.type='text/css';link.rel='stylesheet';link.href=url;consthead=document.getElementsByTagName('head&......
  • 【花雕学AI】ChatGPT的四大语言处理神器:文本生成、问答、创意生成和内容优化的技巧和
    引言:ChatGPT是一个人工智能聊天机器人,它可以理解和交流多种语言,例如中文、英文、日文、西班牙语、法语、德语等。它是由OpenAI开发的,基于GPT-3.5和GPT-4这两个大型语言模型。它不仅可以与用户进行对话,还可以根据用户的指示完成一些语言处理的任务,例如文本生成、问答、创意生成和内......
  • php生成圆形图片
    在PHP中生成圆形图片需要用到GD库提供的图像处理函数。以下是一个简单的示例代码://创建一个200x200的正方形画布$image=imagecreatetruecolor(200,200);//生成背景色为白色的正方形$bg_color=imagecolorallocate($image,255,255,255);imagefill($image,0,......
  • 等差数列生成器
      1classArithmeticProgression:23def__init__(self,begin,step,end=None):4self.begin=begin5self.end=end6self.step=step789def__iter__(self):10result=typ......
  • PHP 之生成名片二维码与vcard格式
    一、vcard格式BEGIN:VCARDVERSION:3.0FN:样子TEL;CELL;VOICE:18333333333TEL;WORK;VOICE:010-66600000TEL;WORK;FAX:010-66600001EMAIL;PREF;INTERNET:[email protected]:http://baidu.comorG:网络工作室ROLE:技术部TITLE:CTOADR;WORK;POSTAL:北四环中路35号;100101REV:20......
  • Vue路由,子路由,动态路由,动态路由参数,路由查询参数
    一、路由、子路由、动态路由子路由、动态路由类似,不同的是子路由同时有路由跳转和页面跳转的,动态路由只有路由跳转,没有页面跳转举例如下:/customerHome 下有 item1 和 item2 两个子路由。import{createRouter,createMemoryHistory,RouteRecordRaw}from'vue-router'......
  • 野指针得生成、危害、清除
    1、野指针得概念::指针指向的位置不可知的(随机、不正确、没有明确限制的)2、野指针生成的三种情况1、指针未定义,就进行*p相关操作2、指针越界访问,知道指向哪,但不是有效值3、指针指向的空间释放(函数的变量作用范围在函数内,返回函数内定义的指针到主函数是无效的,已经被......
  • 4、Ansible模板--用于根据每个主机的不同环境而为生成不同的文件
    ansible模板模板是一个文本文件,可以用于根据每个主机的不同环境而为生成不同的文件模板文件中支持嵌套jinja2语言的指令,来实现变量,条件判断,循环等功能需要使用template模块实现文件的复制到远程主机,但和copy模块不同,复制过去的文件每个主机可以会有所不同jinja2语言http:......
  • 数据生成与采集
    数据生成我们需要先生成测试数据,一份是服务端数据,还有一份是客户端数据【客户端数据】用户行为数据首先我们模拟生成用户行为数据,也就是客户端数据,主要包含用户打开APP、点击、浏览等行为数据用户行为数据:通过埋点上报,后端日志服务器(http)负责接收数据埋点上报数据基本格式:......
  • 计网:实验二 路由器动态路由的配置方法
     一、实验目的: 1.理解动态路由的工作原理;2.学习并掌握动态路由协议RIP的配置;3.学习并掌握动态路由协议OSPF的配置;4.进一步学习路由器的配置命令。二、实验原理:RIP:RoutingInformationProtocol,路由信息协议,是应用较早、使用较普遍的IGP内部网关协议,适用于小型同类网络,是典型......