当前位置: 首页 > news >正文

ProxyGenerator-代理类生成器

ProxyGenerator是JDK-sun包下提供的用于生成动态代理类信息的类,其唯一向外透出的是其静态方法-generateProxyClass(…)。

public class ProxyGenerator {
...
}

学习本篇文章,就是想学习ProxyGenerator如何生成代理类信息的过程。

一、唯一入口-公开静态方法

ProxyGenerator仅提供了一个公开静态方法-方法名为generateProxyClass。从方法入参看,创建代理类信息需传入的参数包括代理类全限定名、代理类实现的接口数组,访问权限标识。实际上,generateProxyClass还有一个重载方法,默认访问权限标识为:public final

public static byte[] generateProxyClass(final String name,Class<?>[] interfaces,int accessFlags){// 根据必须参数实例化ProxyGenerator类ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);// ProxyGenerator对象生成class文件final byte[] classFile = gen.generateClassFile();// 是否要保存生成的class文件if (saveGeneratedFiles) {java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {public Void run() {try {int i = name.lastIndexOf('.');Path path;if (i > 0) {Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));Files.createDirectories(dir);path = dir.resolve(name.substring(i+1, name.length()) + ".class");} else {path = Paths.get(name + ".class");}Files.write(path, classFile);return null;} catch (IOException e) {throw new InternalError("I/O exception saving generated file: " + e);}}});}return classFile;
}
  • ProxyGenerator就只提供了一个私有构造方法,内部使用
  • saveGeneratedFiles:根据"sun.misc.ProxyGenerator.saveGeneratedFiles"系统属性值来选择是否保存代理class文件,默认不保存。
  • 保存文件相关日后可以总结下。
    所以,其实重点就在ProxyGenerator对象的generateClassFile()方法。

二、生成代理类流程

下为ProxyGenerator#generateClassFile()生成具体代理类的代码及注释:

private byte[] generateClassFile() {/* ============================================================* 第一步:组装所有的代理方法, 根据代理签名为Key缓存在proxyMethods属性中。*//** 1.1 向代理类中增加Object类的必须重写的方法。* 这里增加的方法比较早,因此会优先于实现接口的重复方法。*/addProxyMethod(hashCodeMethod, Object.class);addProxyMethod(equalsMethod, Object.class);addProxyMethod(toStringMethod, Object.class);/** 1.2 将接口中的方法信息添加到代理类中。* 注意:前面的方法优先级高于后面接口重复方法。*/for (Class<?> intf : interfaces) {for (Method m : intf.getMethods()) {addProxyMethod(m, intf);}}/** 1.3 校验多个相同方法签名的方法返回值是否兼容*/for (List<ProxyMethod> sigmethods : proxyMethods.values()) {checkReturnTypes(sigmethods);}/* ============================================================* 第二步:组装代理类所有的属性和方法信息,包括构造方法、重写方法、静态初始化方法*/try {// 2.1 增加构造方法methods.add(generateConstructor());for (List<ProxyMethod> sigmethods : proxyMethods.values()) {for (ProxyMethod pm : sigmethods) {// add static field for method's Method object// 2.2 组装代理类所有的属性-指向方法的属性fields.add(new FieldInfo(pm.methodFieldName,"Ljava/lang/reflect/Method;",ACC_PRIVATE | ACC_STATIC));// generate code for proxy method and add it// 2.3 组装代理类所有的重写方法methods.add(pm.generateMethod());}}// 2.4 组装代理类的惊天初始化方法methods.add(generateStaticInitializer());} catch (IOException e) {throw new InternalError("unexpected I/O Exception", e);}if (methods.size() > 65535) {  // 限制方法和属性的个数限制<=65535throw new IllegalArgumentException("method limit exceeded");}if (fields.size() > 65535) {throw new IllegalArgumentException( "field limit exceeded");}/* ============================================================* Step 3: Write the final class file.*//** Make sure that constant pool indexes are reserved for the* following items before starting to write the final class file.* 确保常量池中包含类名、父类名、实现的所有接口名* 常量池来源:类声明信息、方法信息【前面应添加进去】*/cp.getClass(dotToSlash(className));cp.getClass(superclassName);for (Class<?> intf: interfaces) {cp.getClass(dotToSlash(intf.getName()));}/** 常量池只为仅读,不再允许写*/cp.setReadOnly();ByteArrayOutputStream bout = new ByteArrayOutputStream();DataOutputStream dout = new DataOutputStream(bout);try {/** 按照JVM规范写类文件信息*/// u4 magic;dout.writeInt(0xCAFEBABE);// u2 minor_version;dout.writeShort(CLASSFILE_MINOR_VERSION);// u2 major_version;dout.writeShort(CLASSFILE_MAJOR_VERSION);cp.write(dout);             // (write constant pool)// u2 access_flags;dout.writeShort(accessFlags);// u2 this_class;dout.writeShort(cp.getClass(dotToSlash(className)));// u2 super_class;dout.writeShort(cp.getClass(superclassName));// u2 interfaces_count;dout.writeShort(interfaces.length);// u2 interfaces[interfaces_count];for (Class<?> intf : interfaces) {dout.writeShort(cp.getClass(dotToSlash(intf.getName())));}// u2 fields_count;dout.writeShort(fields.size());// field_info fields[fields_count];for (FieldInfo f : fields) {f.write(dout);}// u2 methods_count;dout.writeShort(methods.size());// method_info methods[methods_count];for (MethodInfo m : methods) {m.write(dout);}// u2 attributes_count;dout.writeShort(0); // (no ClassFile attributes for proxy classes)} catch (IOException e) {throw new InternalError("unexpected I/O Exception", e);}return bout.toByteArray();
}

Class文件结构:
在这里插入图片描述

相关文章:

ProxyGenerator-代理类生成器

ProxyGenerator是JDK-sun包下提供的用于生成动态代理类信息的类&#xff0c;其唯一向外透出的是其静态方法-generateProxyClass(…)。 public class ProxyGenerator { ... }学习本篇文章&#xff0c;就是想学习ProxyGenerator如何生成代理类信息的过程。 一、唯一入口-公开静…...

ARM 内存屏障指令

ARM 内存屏障指令 1. dmb (Data Memory Barrier) 数据内存栅栏2. dsb (Data Synchronization Barrier) 数据同步栅栏3. isb (Instruction Synchronization Barrier) 指令同步栅栏4. ARM 内存屏障指令如何选择使用&#xff1f;5. 使用示例5.1. DMB指令示例&#xff1a;5.2. DSB指…...

了解Linux 的 mmap --- 笔记

学习这篇博客&#xff0c;进行了一些归纳Linux下mmap_linux mmap_一个山里的少年的博客-CSDN博客https://blog.csdn.net/qq_56999918/article/details/127070280 >>读取文件 读取文件方法&#xff1a;由操作系统提供的两个方法&#xff0c;read和write来读写文件。 由…...

docker删除容器(步骤详解)

要在Docker中删除容器&#xff0c;需要使用命令docker rm。 下面是详细步骤&#xff1a; 1. 首先&#xff0c;使用docker ps命令查看当前正在运行的容器。这个命令会列出所有正在运行的容器的ID、名称、状态等信息。 如果没有正在运行的容器可以通过docker ps -a 查看当前所…...

boost beast http server 测试

boost beast http client boost http server boost beast 是一个非常好用的库&#xff0c;带上boost的协程&#xff0c;好很多东西是比较好用的&#xff0c;以下程序使用四个线程开启协程处理进入http协议处理。协议支持http get 和 http post #include <boost/beast/cor…...

Android 10.0 系统开启禁用adb push和adb pull传输文件功能

1.使用场景 在进行10.0的系统开发中,在一些产品中由于一些开发的功能比较重要,防止技术点外泄在出货产品中,禁用 adb pull 和adb push等命令 来获取系统system下的jar 和apk 等文件,所以需要禁用这些命令 2.系统开启禁用adb push和adb pull传输文件功能的分析 看了下系统…...

浙大数据结构第七周之07-图4 哈利·波特的考试

基础知识&#xff1a;&#xff08;最短路的前提都是在图中两条边之间的权值非定值&#xff09; &#xff08;一&#xff09;Dijkstra方法 算法实现&#xff1a; …...

vue2-vue项目中你是如何解决跨域的?

1、跨域是什么&#xff1f; 跨域本质是浏览器基于同源策略的一种安全手段。 同源策略&#xff08;sameoriginpolicy&#xff09;&#xff0c;是一种约定&#xff0c;它是浏览器最核心也是最基本的安全功能。 所谓同源&#xff08;即指在同一个域&#xff09;具有以下三个相同点…...

【Paper Reading】DETR:End-to-End Object Detection with Transformers

背景 Transformer已经在NLP领域大展拳脚&#xff0c;逐步替代了LSTM/GRU等相关的Recurrent Neural Networks&#xff0c;相比于传统的RNN&#xff0c;Transformer主要具有以下几点优势 可解决长时序依赖问题&#xff0c;因为Transformer在计算attention的时候是在全局维度进行…...

【rust/入门】windows安装rust gnu环境(折腾)

说在前面 首先说明&#xff0c;我是rust入门选手&#xff0c;之前都是在wsl写rust&#xff0c;突然想在windows下装下rust。windows版本&#xff1a;windows11 22H2原文换源 心路历程 看到教程我陷入了沉默&#xff0c;(官方推荐) 打开Microsoft C Build Tools我开始不解&…...

java面试---字符串相关内容

字符串 1. 什么是Java中的字符串池&#xff08;String Pool&#xff09;&#xff1f;2. String、StringBuilder和StringBuffer之间的区别是什么&#xff1f;3. 如何比较两个字符串的内容是否相等&#xff1f;4、equals和的区别5. String类有哪些常用的方法&#xff1f; 1. 什么…...

MYSQL进阶-事务的基础知识

1.什么是数据库事务&#xff1f; 就是把好几个sql语句打包成一个整体执行&#xff0c;要么全部成功&#xff0c;要么全部失败&#xff01;&#xff01;&#xff01; 事务是一个不可分割的数据库操作序列&#xff0c;也是数据库并发控制的基本单位&#xff0c;其执 行的结果必…...

【C++】C++面向对象,泛型编程总结篇(封装,继承,多态,模板)|(秋招篇)

文章目录 前言如何理解面向对象&#xff1f;如何理解泛型编程&#xff1f;C面向对象的三大特性是什么构造函数有哪几种&#xff1f;讲一下移动构造函数当我们定义一个类 系统会自动帮我们生成哪些函数&#xff1f;标题讲一下类中三类成员&#xff08;公有私有保护&#xff09;三…...

【Github】作为程序员不得不知道的几款Github加速神器

文章目录 背景推荐1&#xff1a;FastGithub推荐2&#xff1a;dev-sidecar推荐3&#xff1a;Watt Toolkit推荐4&#xff1a;篡改猴插件用户脚本1&#xff09;下载安装-->篡改猴 Tampermonkey 插件2&#xff09;下载安装-->Github 增强 - 高速下载 用户脚本 推荐5&#xff…...

react18之08自定义hook (简单的axios-get、修改浏览器title、localStorage、获取滚动条位置、img转换为base64)

目录 react18之自定义hook ()01&#xff1a;自定义一个 简单的axios hook 发起get请求useHttp.jsx使用useHttp hook效果 02&#xff1a;自定义一个 修改浏览器title hook03&#xff1a;自定义一个 localStorage(获取、存储、移除) hookuseLocalStorage.jsx使用hook效果 04&…...

对CommonJS、AMD、CMD、ES Module的理解

CommonJS 常用于&#xff1a;服务器端&#xff0c;node&#xff0c;webpack 特点&#xff1a;同步/运行时加载&#xff0c;磁盘读取速度快 语法&#xff1a; // 1. 导出&#xff1a;通过module.exports或exports来暴露模块 module.exports { attr1, attr2 } ex…...

JVM之类加载与字节码(二)

3. 编译期处理 什么是语法糖 所谓的 语法糖 &#xff0c;其实就是指 java 编译器把 *.java 源码编译为 *.class 字节码的过程中&#xff0c;自动生成 和转换的一些代码&#xff0c;主要是为了减轻程序员的负担&#xff0c;算是 java 编译器给我们的一个额外福利&#xff08;给…...

安装linux操作系统

安装虚拟机的步骤&#xff1a; 安装linux系统 之后开启虚拟机 之后重启&#xff0c;打开虚拟机&#xff0c;登录root账号...

【SpringBoot】知识

.第一个程序HelloWorld 项目创建方式&#xff1a;使用 IDEA 直接创建项目 1、创建一个新项目 2、选择spring initalizr &#xff0c; 可以看到默认就是去官网的快速构建工具那里实现 3、填写项目信息 4、选择初始化的组件&#xff08;初学勾选 Web 即可&#xff09; 5、填…...

react ant add/change created_at

1.引入ant的 Table import { Table, Space, Button, message } from antd; 2.获得接口的数据的时候增加上创建时间 const response await axios.get(${Config.BASE_URL}/api/v1/calculation_plans?token${getToken()});if (response.data.message ok) {const data respon…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

ubuntu22.04有线网络无法连接,图标也没了

今天突然无法有线网络无法连接任何设备&#xff0c;并且图标都没了 错误案例 往上一顿搜索&#xff0c;试了很多博客都不行&#xff0c;比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动&#xff0c;重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式

pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图&#xff0c;如果边框加在dom上面&#xff0c;pdf-lib导出svg的时候并不会导出边框&#xff0c;所以只能在echarts图上面加边框 grid的边框是在图里…...