javassist学习

news2024/11/18 19:59:39

 

        Java 字节码以二进制的形式存储在 .class 文件中,每一个 .class 文件包含一个 Java 类或接口。Javaassist 就是一个用来 处理 Java 字节码的类库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深入的了解。同时也可以去生成一个新的类对象,通过完全手动的方式。

        在 Javassist 中,类 Javaassit.CtClass 表示 class 文件。一个 GtClass (编译时类)对象可以处理一个 class 文件

看代码示例:

加入依赖:

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

使用 Javassist 创建一个 class 文

代码:

package com.sqz.javassist;

import javassist.*;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CreatePerson {

    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.makeClass("com.sqz.javassist.Persion");
        //增加成员变量
        CtField name = new CtField(pool.get("java.lang.String"), "name", ctClass);
        name.setModifiers(Modifier.PRIVATE);
        ctClass.addField(name,CtField.Initializer.constant("xiaoming"));
        ctClass.addMethod(CtNewMethod.setter("setName",name));
        ctClass.addMethod(CtNewMethod.getter("getName",name));
        //增加无参构造器
        CtConstructor noArgConstructor = new CtConstructor(new CtClass[]{}, ctClass);
        noArgConstructor.setBody("{name=\"xiaoming\";}");
        ctClass.addConstructor(noArgConstructor);
        //增加有参构造器
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String")}, ctClass);
        // $0=this / $1,$2,$3... 代表方法参数
        ctConstructor.setBody("{$0.name=$1;}");
        ctClass.addConstructor(ctConstructor);
        //增加方法
        CtMethod printName = new CtMethod(CtClass.voidType, "printName", new CtClass[0], ctClass);
        printName.setModifiers(Modifier.PUBLIC);
        printName.setBody("{System.out.println(name);}");
        ctClass.addMethod(printName);
        //将生成的class输出到文件
       // ctClass.writeFile("/Users/mac/workspace/dubbo-dubbo-3.0.2/dubbo-demo-sqz/src/main/java/");

        //实例化对象并调用
        Object o = ctClass.toClass().newInstance();
        Method setName = o.getClass().getMethod("setName", String.class);
        Method getName = o.getClass().getMethod("getName");
        Method printName1 = o.getClass().getMethod("printName");
        setName.invoke(o,"老王");
        Object invoke = getName.invoke(o);
        System.out.println("getName->"+invoke);
        printName1.invoke(o);

    }


}

运行上面代码会生成class文件

 class文件内容如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sqz.javassist;

public class Persion {
    private String name = "xiaoming";

    public void setName(String var1) {
        this.name = var1;
    }

    public String getName() {
        return this.name;
    }

    public Persion() {
        this.name = "xiaoming";
    }

    public Persion(String var1) {
        this.name = var1;
    }

    public void printName() {
        System.out.println(this.name);
    }
}

ClassPool需要关注的方法:

  1. getDefault : 返回默认的ClassPool 是单例模式的,一般通过该方法创建我们的ClassPool;
  2. appendClassPath, insertClassPath : 将一个ClassPath加到类搜索路径的末尾位置 或 插入到起始位置。通常通过该方法写入额外的类搜索路径,以解决多个类加载器环境中找不到类的尴尬;
  3. toClass : 将修改后的CtClass加载至当前线程的上下文类加载器中,CtClass的toClass方法是通过调用本方法实现。需要注意的是一旦调用该方法,则无法继续修改已经被加载的class
  4. get , getCtClass : 根据类路径名获取该类的CtClass对象,用于后续的编辑。

CtClass需要关注的方法:

  1. freeze : 冻结一个类,使其不可修改;
  2. isFrozen : 判断一个类是否已被冻结;
  3. prune : 删除类不必要的属性,以减少内存占用。调用该方法后,许多方法无法将无法正常使用,慎用;
  4. defrost : 解冻一个类,使其可以被修改。如果事先知道一个类会被defrost, 则禁止调用 prune 方法;
  5. detach : 将该class从ClassPool中删除;
  6. writeFile : 根据CtClass生成 .class 文件;
  7. toClass : 通过类加载器加载该CtClass。

CtMethod中的一些重要方法:

  1. insertBefore : 在方法的起始位置插入代码;
  2. insterAfter : 在方法的所有 return 语句前插入代码以确保语句能够被执行,除非遇到exception;
  3. insertAt : 在指定的位置插入代码;
  4. setBody : 将方法的内容设置为要写入的代码,当方法被 abstract修饰时,该修饰符被移除;
  5. make : 创建一个新的方法。

CtField中的一些重要方法 

  1. setModifiers: 在方法的起始位置插入代码;
  2. setGenericSignature: 在方法的所有 return 语句前插入代码以确保语句能够被执行,除非遇到exception;
  3. make : 创建一个新的方法。

 修改现有的类对象

代码如下

package com.sqz.javassist;


public class UserService {

    public void printUser(){
        System.out.println("user");
    }

}
z.javassist;

import javassist.*;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class UpdatePerson {

    public static void main(String[] args) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get("com.sqz.javassist.UserService");

        //修改方法 类似aop
        CtMethod printUser = ctClass.getDeclaredMethod("printUser");
        printUser.insertBefore("System.out.println(\"before\");");
        printUser.insertAfter("System.out.println(\"after\");");

        //增加方法
        CtMethod show = new CtMethod(CtClass.voidType, "show", new CtClass[0], ctClass);
        show.setBody("{System.out.println(\"show\");}");
        ctClass.addMethod(show);

        //增加字段 这种更简单
        CtField name = CtField.make("private String name = \"老王\";", ctClass);
        ctClass.addField(name);

        //增加方法
        CtMethod getName = CtNewMethod.make("public String getName() {\n" +
            "        return name;\n" +
            "    }", ctClass);
        ctClass.addMethod(getName);


        Object o = ctClass.toClass().newInstance();
        Method printUser1 = o.getClass().getMethod("printUser");
        printUser1.invoke(o);


        Method show1 = o.getClass().getMethod("show");
        show1.invoke(o);


        Method getName1 = o.getClass().getMethod("getName");
        Object invoke = getName1.invoke(o);
        System.out.println(invoke);

    }

}

一般会遇到的使用场景应该是修改已有的类。比如常见的日志切面,权限切面等

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

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

相关文章

第29届中国国际广告节,酷开科技喜提三奖

第29届中国国际广告节&#xff0c;酷开科技喜提三奖 12月21日至12月23日&#xff0c;在风景如画的鹭岛厦门&#xff0c;第29届中国国际广告节于厦门国际会展中心隆重举行。经过几十年的高歌前行&#xff0c;中国国际广告节业已成为业界的盛会&#xff0c;更是中国广告业发展的…

(十)VUEElement

一、 VUE 1. 概述 Vue 是一套前端框架&#xff0c;免除原生JavaScript中的DOM操作&#xff0c;简化书写。基于MVVM(Model-View-ViewModel)思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注点放在数据上。官网&#xff1a;https://cn.vuejs.org 2. 快速入门 &#…

CRM管理系统哪个好用?这五款CRM系统值得推荐

选择一款合适的CRM系统&#xff0c;可以有效解决企业生产经营中分散的数据、不规则的工作流程、缺乏客户服务、销售预测不准确、远程工作效率低、错误的客户沟通、几乎没有销售和市场合作、报告不足等方面的业务难题。 CRM系统的选型可以从以下方面考虑&#xff1a; 下面分享几…

Faster RCNN网络源码解读(Ⅺ) --- 预测结果后处理及预测过程(完结撒花)

目录 一、回顾以及本篇博客内容概述 二、代码解析 2.1 ROIHead类&#xff08;承接上篇博客的2.1节&#xff09; 2.1.1 初始化函数 __init__回顾 2.1.2 正向传播forward回顾及预测结果后处理 2.1.3 postprocess_detections 2.2 FasterRCNNBase类前向传播过程 2.3 Genera…

MySQL Workbench基本用法

MySQL Workbench相当于SQL语言的解释器 目录 1 打开 2 连接数据库 3 创建数据库 4 创建数据表 4.1 字段类型 4.2 字段选项 4.3 其他 5 操作表中的数据 5.1 添加 5.2 更改 5.3 删除 6 代码编辑器 7 保存sql代码 8 加载sql代码 1 打开 搜索MySQL …

滑动窗口题型

先看一个题目&#xff1a;题目描述 题目描述&#xff1a;给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 例如&#xff1a; 输入&#xff1a;s "ADOBECODE…

移动Web【rem、flexible、Less、vw / vh】

文章目录remflexibleLessvw / vhrem 网页效果 屏幕宽度不同&#xff0c;网页元素尺寸不同&#xff08;等比缩放&#xff09; px单位或百分比布局可以实现吗&#xff1f; px单位是绝对单位百分比布局特点宽度自适应&#xff0c;高度固定 适配方案 remvw / vh rem单位 相对单位…

Homekit智能家居DIY之智能通断开关

智能通断器&#xff0c;也叫开关模块&#xff0c;可以非常方便地接入家中原有开关、插座、灯具、电器的线路中&#xff0c;通过手机App或者语音即可控制电路通断&#xff0c;轻松实现原有家居设备的智能化改造。 随着智能家居概念的普及&#xff0c;越来越多的人想将自己的家改…

SQL SELECT DISTINCT 语句

SELECT DISTINCT 语句用于返回唯一不同的值。 SQL SELECT DISTINCT 语句 在表中&#xff0c;一个列可能会包含多个重复值&#xff0c;有时您也许希望仅仅列出不同&#xff08;distinct&#xff09;的值。 DISTINCT 关键词用于返回唯一不同的值。 SQL SELECT DISTINCT 语法 …

如何从零开始开发一个小程序

如何从零开始开发一个小程序开始申请账号开发设置开发工具新建小程序阅读文档模版语法项目架构开始编写基础语法wx:for循环wx:if判断页面导航自定义组件引用样式修改单行、多行省略flex布局grid布局发布开始 申请账号 小程序注册页 开发设置 登录 小程序后台 &#xff0c;…

【Vue2+Element ui通用后台】Mock.js

文章目录Mock.js首页数据调用mock数据并完成布局Mock.js Mock.js 官网 Mockjs Github地址 作用&#xff1a;生成随机数据&#xff0c;拦截 Ajax 请求 使用npm i mockjs进行安装&#xff0c;然后在 api 下新建 mock.js import Mock from mockjs// 定义mock请求拦截 Mock.mock…

【CPU是如何执行程序的?】

CPU是如何执行程序的&#xff1f;1、、硬件结构介绍1.1、CPU1.2、内存1.3、总线1.4、输入/输出设备二、程序执行的基本过程三、a11执行的详细过程现代计算机的基本结构为五个部分&#xff1a;CPU、内存、总线、输入/输出设备。或许你了解了这些概念&#xff0c;但是你知道a11在…

leetcode每日一题(python)2023-1.2 1801. 积压订单中的订单总数 (middle)

leetcode每日一题 &#x1f6a9; 学如逆水行舟&#xff0c;不进则退。 —— 《增广贤文》 题目描述&#xff1a; 给你一个二维整数数组 orders &#xff0c;其中每个 orders[i] [price(i), amount(i), orderType(i)] 表示有 amount(i)( )笔类型为 orderType(i) 、价格为 pric…

没错,这是2023年开篇!!

不知不觉小G和Gopher们一起相伴着又走过了一个年头&#xff0c;迎来了2023年。回望这一年我们有遗憾&#xff1a;因疫情的原因没能和大家在线下2022 GopherChina大会相聚一堂我们也有快乐与成就&#xff1a;在经过一番调查、统计、分析后发布了《2022 Q2 GO开发者问卷调查结果》…

阿里、京东、百度“激战”互联网医疗

与衣食住行一样&#xff0c;医疗需求同样对人们的生存具有重要意义。医疗行业经过多年的发展&#xff0c;也已经发生了翻天覆地的变化。除了线下医疗日益完善之外&#xff0c;互联网医疗也随着互联网的飞速发展而实现了快速起飞。现如今&#xff0c;互联网医疗已经逐步成为了线…

沿全尺寸模型水平轴 MHK 涡轮机(DOE RM1)叶片性能表征计算(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 该存储库包括 MATLAB 脚本和输入文件示例&#xff0c;用于沿全尺寸模型水平轴 MHK 涡轮机叶片计算 3D AOA、CL 和 CD。该脚本是…

idea插件代码生成工具EasyCode

idea插件代码生成工具EasyCode1. EasyCode下载安装2. EasyCode配置模板2.1 配置路径2.2 配置文件2.2.1. controller.java2.2.2. entity.java2.2.3. mapper.java2.2.4. service.java2.2.5. serviceImpl.java2.2.6. mapper.xml3. 构建SpringBoot项目3.1 初始化数据库3.2 创建项目…

git push -u origin master报错(vscode)

Missing or invalid credentials. Error: connect ECONNREFUSED /run/user/1000/vscode-git-e10c66c0ac.sock at PipeConnectWrap.afterConnect [as oncomplete] (node:net:1157:16) { errno: -111, code: ‘ECONNREFUSED’, syscall: ‘connect’, address: ‘/run/user/1000/…

Docker 镜像仓库的构建与镜像管理

目录 Docker 私有仓库 1. 简介 2. 构建 Docker 私有仓库 &#xff08;1&#xff09;部署环境 &#xff08;2&#xff09;服务端部署 &#xff08;3&#xff09;客户端配置 &#xff08;4&#xff09;私有镜像仓库测试 Dockerfile 1. 概述 2. Dockerfile 的组成 3. D…

对序表记录固定排序

【问题】 PRODUCT_ID, PRODUCT_NAME 100 Nokia 200 IPhone 300 Samsung 400 LG I want to display the records like below: PRODUCT_ID, PRODUCT_NAME 300 Samsung 200 IPhone 100 Nokia 400 LG【回答】 固定排序有时排序依据会经常变动&#xff0c;并且…