javassist动态生成,修改字节码 demo

news2024/11/26 0:44:28

Javassist 是一个开源的分析、编辑和创建 Java 字节码的类库,被广泛用于程序性的类文件操作和运行时 AOP 框架,能动态改变类的结构,或者动态生成类。

关于javassist和反射

Javassist 不是通过反射来实现的,而是通过直接操作字节码来实现的。

在 Java 中,每个类都会被编译成一个或多个字节码文件(.class 文件)。这些字节码文件包含了 Java 虚拟机(JVM)需要执行类中的代码的所有信息。Javassist 可以读取这些字节码文件,修改它们,然后写回去,或者直接创建新的字节码文件。这使得 Javassist 能够在运行时动态地创建和修改类。

反射(Reflection)则是 Java 提供的一个特性,它允许程序在运行时获取类的信息(如类名、方法、字段等),并动态地调用方法、访问字段等。与 Javassist 不同,反射不能修改类的结构,只能动态地使用类。

所以,尽管 Javassist 和反射都能在运行时动态地操作类,但是它们的实现机制和能力是不同的。

下面是些使用javassist的小demo

public class JavaSsistDemo1 {
    public static void main(String[] args) throws Exception {
        // 获取类池
        ClassPool pool = ClassPool.getDefault();
        // 创建类
        CtClass cc = pool.makeClass("com.example.GeneratedPOJO");

        // 创建字段,字段的类型,字段名称
        CtField fooField = new CtField(pool.get("java.lang.String"), "foo", cc);
        //设置私有化
        fooField.setModifiers(Modifier.PRIVATE);
        //类中添加该字段
        cc.addField(fooField);

        //创建get方法
        cc.addMethod(CtNewMethod.getter("getFoo", fooField));
        //创建set方法
        cc.addMethod(CtNewMethod.setter("setFoo", fooField));

        CtMethod helloMethod = CtNewMethod.make(
                "public void hello() { System.out.println(\"Hello Javassist!\"); }",
                cc
        );
        cc.addMethod(helloMethod);

        //可以选择写入磁盘,也可以不写入直接在内存中使用
        cc.writeFile("J:\\javassist\\javassist-01\\target\\classes\\");

        //获得类对象
        Class<?> clazz = cc.toClass();

        //这里用Class.forName("")也是可以的,就是没有必要
        //Class<?> clazz1 = Class.forName("com.example.GeneratedPOJO");
        //实例化
        Object instance = clazz.newInstance();
        Method getter = clazz.getMethod("getFoo");
        System.out.println(getter.invoke(instance));

        Method hello = clazz.getMethod("hello");
        hello.invoke(instance);
        //如果方法有返回值
        String result = (String) hello.invoke(instance);
        System.out.println(result);  // prints "Hello Javassist!"
    }
//    public static void main(String[] args) throws Exception {
//        // 获取类池
//        ClassPool pool = ClassPool.getDefault();
//        // 创建类
//        CtClass ctClass = pool.makeClass("com.com.example.GeneratedPOJO");
//        // 创建⽅法
//        // 1.返回值类型 2.⽅法名 3.形式参数列表 4.所属类
//        CtMethod ctMethod = new CtMethod(CtClass.voidType, "execute", new
//                CtClass[]{}, ctClass);
//        // 设置⽅法的修饰符列表
//        ctMethod.setModifiers(Modifier.PUBLIC);
//        // 设置⽅法体
//        ctMethod.setBody("{System.out.println(\"hello world\");}");
//        // 给类添加⽅法
//        ctClass.addMethod(ctMethod);
//        // 调⽤⽅法
//        Class<?> aClass = ctClass.toClass();
//        Object o = aClass.newInstance();
//        Method method = aClass.getDeclaredMethod("execute");
//        method.invoke(o);
//    }
}

cc.toClass() 是动态创建并加载类,而 Class.forName() 是加载已经存在的类。

关于Mybatis的demo,我们当里面只有一个方法

public static void main(String[] args) throws CannotCompileException, IllegalAccessException, InstantiationException {
        //模仿Mybatis动态创建实现类

        //获取类池
        ClassPool pool=ClassPool.getDefault();
        //制造类
        CtClass ctClass=pool.makeClass("com.example.UserDaoImpl");
        //制造接口
        //CtClass ctInterface=pool.makeClass("com.example.UserDao");
        //注意javassits的类加载器和UserDao加载器可能不是同一个
        
        //让类实现接口 
        //这里其实用CtClass ctInterface = pool.get("com.example.UserDao");更加合适
        CtClass ctInterface = pool.get("com.example.UserDao");
        ctClass.addInterface(ctInterface);//UserDaoImpl implements UserDao
        //实现接口中的方法,这个比较麻烦,这里好比我们已经知道了所有方法什么的
        //制造方法
        CtMethod ctMethod=CtMethod.make("public void delete(){System.out.println(\"delete biubiubiu\");}",ctClass);
        //将方法添加到类中
        ctClass.addMethod(ctMethod);
        //在内存中生成类,同时将生成的类加载到JVM当中
        Class<?> aClass = ctClass.toClass();
        UserDao userDao=(UserDao) aClass.newInstance();
        System.out.println(userDao.getClass());
        userDao.delete();

    }

模拟实现Mapper接口所有方法

public static void main(String[] args) throws CannotCompileException, IllegalAccessException, InstantiationException, NotFoundException {
        //模仿Mybatis动态创建实现类

        //获取类池
        ClassPool pool=ClassPool.getDefault();
        //制造类
        CtClass ctClass=pool.makeClass("com.example.UserDaoImpl");
        //获取接口
        CtClass ctInterface=pool.get("com.example.UserDao");
        //让类实现接口
        ctClass.addInterface(ctInterface);//UserDaoImpl implements UserDao
        //实现接口中所有的方法
        //获取接口中所有的方法
        Method[] methods=UserDao.class.getDeclaredMethods();
        //遍历中实现抽象方法,然后把方法放到了类中
        Arrays.stream(methods).forEach(method->{
            //method是接口中所有的抽象方法
            //把method抽象方法给实现了
            CtMethod ctMethod=null;
            try {
                StringBuilder methodCode=new StringBuilder();
                methodCode.append("public ");//修饰符列表
                methodCode.append(method.getReturnType().getName());//追加返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName());//追加方法名
                methodCode.append("(");

                //也许方法有参数
                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(1111);");
                //动态添加return语句
                String simpleName = method.getReturnType().getSimpleName();//返回值类型的简类名
                if("void".equals(simpleName)){

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

        });

        //在内存中生成类,同时将生成的类加载到JVM当中
        Class<?> aClass = ctClass.toClass();
        //创建对象
        UserDao userDao=(UserDao) aClass.newInstance();
        System.out.println(userDao.getClass());
        //调用方法
        userDao.delete();
        userDao.selectasd("as");

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/539005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python3+telnetlib实现简单自动测试

1 telnetlib介绍 1.1 简介 官方介绍文档&#xff1a;telnetlib – Telnet 客户端 — Python 3.9.6 文档 telnetlib 模块提供一个实现Telnet协议的类 Telnet。 1.2 库常用函数及使用 1.2.1 建立连接 建立连接有两种方式&#xff1a;1、实例化函数的时候&#xff0c;将可选参数…

PSP - AlphaFold2 Multimer 的 Heteromer (异源多聚体) MSA 逻辑

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/130733737 同源多聚体 (Homomer) 是由相同的蛋白质亚基组成的,而异源多聚体 (Heteromer) 是由不同的蛋白质亚基组成的。同源多聚体的亚基之间通常有对称的相…

网络安全真的有那么好吗

网络安全是一个永远不会完美的领域&#xff0c;因为网络空间是一个开放、动态、复杂的环境&#xff0c;存在着许多安全威胁和攻击手段。虽然现代的安全技术和防御措施已经很强大&#xff0c;但黑客和病毒等攻击手段也在不断升级&#xff0c;不断打破现有的安全防御措施。因此&a…

论-如何更好的帮助小伙伴们写出更多高质量的论文

开篇一张图&#xff0c;告诉大家&#xff0c;哥哥我身体依然倍棒&#xff0c;依然奋战在一线。 前言 最近几个月一直在加班为小伙伴们创造价值&#xff0c;已经帮助上百位小伙伴解决了论文的“烦恼”与“忧愁”&#xff0c;但是我想说的是&#xff0c;哥哥真的苦啊&#xff0c;…

【分布族谱】泊松分布和二项分布、正态分布的关系

文章目录 泊松分布和二项分布的关系和正态分布的关系 泊松分布 如果在有限时间 ( 0 , 1 ) (0,1) (0,1)内进行 n n n次伯努利实验&#xff0c;那么每次伯努利实验所占用的时间为 1 n \frac{1}{n} n1​&#xff0c;按照自然规律&#xff0c;一件事情肯定是时间越长越容易发生&am…

chatgpt赋能Python-pycharm改名字

PyCharm更名为JetBrains PyCharm——专属Python开发者的最佳IDE JetBrains PyCharm是一款Python开发者最喜欢使用的IDE之一。然而&#xff0c;在2021年初&#xff0c;这款世界著名的Python IDE进行了一次重大更名——PyCharm更名为JetBrains PyCharm。在这篇文章中&#xff0c…

Rust每日一练(Leetday0003) 整数反转、字串转整数、回文数

目录 7. 整数反转 Reverse Integer &#x1f31f;&#x1f31f; 8. 字符串转换整数 String-to-integer (atoi) &#x1f31f;&#x1f31f; 9. 回文数 Palindrome Number &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Rust每日一练 专栏 Golang每日一…

chatgpt赋能Python-pycharm提取数据

PyCharm提取数据指南 PyCharm作为一款强大的Python IDE&#xff0c;在数据科学和数据分析领域广受欢迎。它不仅可以用于Python代码开发&#xff0c;还能够提高数据的处理效率。本文将介绍如何在PyCharm中使用Python代码提取数据&#xff0c;以及探讨如何最大化地发挥其数据处理…

chatgpt赋能Python-pycharm行数

PyCharm行数&#xff1a;如何轻松管理您的代码库 作为一个有10年Python编程经验的工程师&#xff0c;我知道管理庞大代码库的挑战。在这种情况下&#xff0c;行数管理是一个非常重要的方面。幸运的是&#xff0c;有很多现代的集成开发环境&#xff08;IDE&#xff09;可以帮助…

chatgpt赋能Python-pycharm粘贴把空格识别成行

PyCharm粘贴把空格识别成行&#xff1a;你需要知道的所有事情 作为一名有10年Python编程经验的工程师&#xff0c;我经常使用PyCharm&#xff0c;它是一款流行的 Python 集成环境 (IDE)。今天&#xff0c;我想分享一些有关 PyCharm 粘贴把空格识别成行的信息。 什么是PyCharm…

Windows活动目录以及部分Windows网络应用服务器

一.本地用户和组 Windows Server2008本地用户与组: 用户:就是包含用户名、密码、权限以及说明。 用户组:具有相同性质的用户归结在一起&#xff0c;统一授权&#xff0c;组成用户组。 用户组分类:全局组、本地组、特殊组。 各组名及其权限&#xff1a; Administrators&#…

不用等待列表,马上解锁New Bing GPT-4功能

大家好&#xff0c;我是可夫小子&#xff0c;关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。加&#xff1a;keeepdance&#xff0c;备注&#xff1a;chatgpt&#xff0c;拉你进群。 今年1月份&#xff0c;微软投资OpenAI 100亿之后&#xff0c;就迅速把ChatGPT的能力接…

chatgpt赋能Python-pycharm添加numpy库

PyCharm添加Numpy库 PyCharm是一款功能强大的Python集成开发环境&#xff0c;广泛应用于Python程序开发和数据分析领域。Numpy是Python中著名的科学计算库&#xff0c;包括数组、矩阵、数学函数等模块&#xff0c;是数据科学领域中不可或缺的工具。 本篇SEO文章将介绍如何在P…

Android之 Activity活动详解

一 四大组件 1.1 Activity组件&#xff0c;它一个单独的窗口&#xff0c;程序流程都必须在Activity中运行。 1.2 service组件&#xff0c;用于在后台完成用户指定的操作。 1.3 content provider组件&#xff0c;会为所有的应用准备一个内容窗口&#xff0c;并且保留数据库、…

《程序员面试金典(第6版)》面试题 16.24. 数对和(哈希映射,双指针)

题目描述 设计一个算法&#xff0c;找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。 题目传送门 示例 1: 输入: nums [5,6,5], target 11 输出: [[5,6]]示例 2: 输入: nums [5,6,5,6], target 11 输出: [[5,6],[5,6]]提示&#xff1a; nums.length &…

抖音SEO矩阵系统源码开发(一)

抖音seo矩阵营销系统/抖音SEO矩阵号管理系统/抖音霸屏源码开发搭建&#xff0c;抖音官方团队大力推广抖音SEO生态&#xff0c;我们应如何布局开发抖音SEO矩阵系统&#xff0c;来达到账号排名优化的效果&#xff0c;很显然&#xff0c;账号关键词起到了很关键的作用。首先&#…

强化学习笔记-06 Temporal-Difference TD时分学习

本文是博主对《Reinforcement Learning- An introduction》的阅读笔记&#xff0c;不涉及内容的翻译&#xff0c;主要为个人的理解和思考。 TD学习是现代强化学习方法的核心&#xff0c;其是蒙特卡罗法和动态规划法的结合&#xff0c;一方面&#xff0c;其同蒙特卡罗法一样&…

opengauss的pull-request

一个pull-request其实是一个分支&#xff0c;而不是一个提交&#xff0c;所以一个pull-request里可以容纳多个提交&#xff0c;pull-request的提交过程原理很像&#xff08;应该就是&#xff09;rebase一个分支&#xff0c;然后将这个分支合入目标分支。 下面是我修改代码并且…

【软件测试】软件测试岗位会越来越少吗?

我的整体意见是测试岗位不会变少&#xff0c;反而相对于其他岗位会变的更重要一些。 首先纠正一个非常非常错误的观念。测试和测试开发是两个岗位&#xff1f;No&#xff0c;不是的。测试开发是属于测试的。 测试开发只不过是使用类似于开发的技术和能力&#xff0c;来达到测…

第十四章 使用Postfix与Dovecot部署邮件系统

文章目录 第十四章 使用Postfix与Dovecot部署邮件系统一、电子邮件系统1、常见的邮件协议2、注意事项 二、部署电子邮件系统1、部署基础的电子邮件系统&#xff08;1&#xff09;、配置服务器主机名称&#xff08;2&#xff09;、配置服务器的DNS地址&#xff08;3&#xff09;…