恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

ASM 自定义属性(Attribute)机制实战:用 `Attribute` 子类扩展类文件格式,CodeGuide 附录 A.3 深度解析

  • 首页
  • 资讯中心
  • /
  • ASM 自定义属性(Attribute)机制实战:用 `Attribute` 子类扩展类文件格式,CodeGuide 附录 A.3 深度解析

相关资讯

Lighthouse挂载COS实现静态资源零侵入托管 2026/9/24 6:27:53
DA14585烧录失败根源解析:SPI Flash映射与S19协议实战指南 2026/9/24 6:27:53
工业大模型:赋能制造业智能化升级的核心引擎 2026/9/24 6:27:53

最新资讯

2026年硬核最值得推荐的5款降AI率软件
Altium Designer 22 STEP导出带丝印,高效交付PCB 3D模型
SG90舵机与电位器闭环控制:从PWM原理到多平台实战
夜间行人检测数据集:1000张实拍图+三格式标签+YOLO11跨平台训练
PCIe Retimer接收器眼图裕量检测实战指南
【JavaSE】初识 Java

今日推荐

JavaWeb购物车系统实现:基于Session存储的完整工程示例
面向对象综合训练:从图书管理系统掌握封装、继承与多态
Lombok与JDK版本冲突引发NoSuchFieldError:根因排查与修复指南

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

ASM 自定义属性(Attribute)机制实战:用 `Attribute` 子类扩展类文件格式,CodeGuide 附录 A.3 深度解析

发布时间:2026/9/24 6:27:53
ASM 自定义属性(Attribute)机制实战:用 `Attribute` 子类扩展类文件格式,CodeGuide 附录 A.3 深度解析 文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载本篇文章基于 CodeGuide 仓库中 ASM 文档的 A.3 属性 一章系统讲解 JVM 类文件格式中属性Attribute这一可扩展机制的底层原理以及 ASM 中Attribute类的完整用法。读完本文你将掌握类、字段、方法三级属性在 ASM 事件模型中的访问入口ClassReader对标准属性与非标准属性的默认处理策略以及如何通过编写Attribute子类实现自定义属性的解码与重新编码并正确注册到ClassReader.accept中。属性机制类文件格式留给扩展的后门在 2.1 结构 一章中可以看到一个已编译类的整体结构由多个部分组成类描述修饰符、名字、超类、接口、常量池、源文件名、封装的类引用、注释、内部类以及类中声明的每个字段和方法各自对应的部分。其中类、字段、方法这三层结构上都留有一个带星号的属性*槽位星号表示零个或多个已编译类的整体结构*表示零个或多个 ├── 修饰符、名字、超类、接口 ├── 常量池数值、字符串和类型常量 ├── 源文件名可选 ├── 封装的类引用 ├── 注释* ├── 属性* ├── 内部类* ├── 字段* 修饰符、名字、类型 │ 注释* │ 属性* └── 方法* 修饰符、名字、返回类型与参数类型 注释* 属性* 编译后的代码属性机制正是 JVM 规范为类文件格式留出的可扩展后门可以将任意属性关联到类、字段和方法。在引入新特性时这种可扩展机制对于扩展类文件格式非常有用。例如它已经被用于扩展这一格式以支持注释Annotations、泛型Signature 属性、栈映射帧StackMapTable等 JVM 新特性——这些特性都是以标准属性的形式注入类文件的。这一机制还可由用户使用而不只是由 JVM 规范制定者使用。不过自从在 Java 5 中引入注释之后注释的使用就比属性容易得多——注释有语言级语法支持可以被编译器、工具链和反射 API 统一处理。因此如果你真的需要使用自己的属性或者必须管理由别人定义的非标准属性就需要在 ASM 中用Attribute类来完成。默认行为ClassReader 如何对待未知属性默认情况下ClassReader类会为它找到的每个标准属性创建一个Attribute实例并以这个实例为参数调用visitAttribute方法。至于调用的是ClassVisitor、FieldVisitor还是MethodVisitor的该方法则取决于属性出现的上下文——也就是说ASM 的事件模型在类、字段、方法三个层级上分别暴露了属性访问入口详见 2.2 接口和组件 与 3.2 接口和组件 中的ClassVisitor.visitAttribute、FieldVisitor.visitAttribute、MethodVisitor.visitAttribute方法。对于非标准未知属性Attribute实例中保存的是这个属性的原始内容其形式为一个私有的字节数组。ClassWriter在访问这种未知属性时会将这个原始字节数组原样复制到它构建的新类中。默认复制行为为何依赖 2.2.4 节的优化这里有一个非常关键的隐含前提这一默认行为只有在使用 2.2.4 节 介绍的优化时才是安全的。所谓 2.2.4 节的优化指的是ClassReader与ClassWriter互相持有对方引用时的常量池复制优化ClassReader cr new ClassReader(b1); ClassWriter cw new ClassWriter(cr, 0); ChangeVersionAdapter ca new ChangeVersionAdapter(cw); cr.accept(ca, 0); byte[] b2 cw.toByteArray();当ClassReader检测到它返回的MethodVisitor来自一个ClassWriter时意味着该方法的内容不会被转换ClassReader就不会去分析方法内容、生成相应事件而是直接把ClassWriter中表示该方法的字节数组复制过去。原始属性内容本质上是一段与常量池索引交织的字节序列——属性内部往往通过索引引用常量池中的 UTF8 字符串等常量。如果不使用复制常量池优化ClassWriter会构建一个全新的常量池原来属性字节中记录的常量池索引就会失效原内容可能会与类编写器创建的新常量池不一致从而导致类文件被损坏。而使用该优化时原类中定义的所有常量都会被复制到转换后的类中属性字节内的索引得以原样保留。所以这一优化除了提高性能外还是保证未知属性原样复制安全性的另一重要原因。关于该优化的性能收益A.5 性能 一章给出的基准数据显示复制常量池优化可提速 15%20%。默认行为的局限性内容不透明默认情况下非标准属性会以它在已转换类中的形式被复制它的内容对 ASM 和用户来说是完全不透明的——ASM 不做任何解析你也无法读取或修改其中的业务信息。如果只是路过某个类、不希望破坏其自定义属性这个默认行为是够用的但如果你需要访问属性内容就必须主动介入定义一个Attribute子类实现对该属性原始内容的解码read与重新编码write在ClassReader.accept方法中传送这个类的一个原型实例使ClassReader可以解码这一类型的属性。实战编写 CommentAttribute 自定义属性下面用文档中的完整示例来演示。假设我们要实现一个设想的注释特性它的原始内容是一个short值引用存储在常量池中的一个 UTF8 字符串。对应的Attribute子类如下class CommentAttribute extends Attribute { private String comment; public CommentAttribute(final String comment) { super(Comment); this.comment comment; } public String getComment() { return comment; } Override public boolean isUnknown() { return false; } Override protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { return new CommentAttribute(cr.readUTF8(off, buf)); } Override protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { return new ByteVector().putShort(cw.newUTF8(comment)); } }逐段剖析这个类构造器与属性名super(Comment)将属性名固定为Comment。属性名在类文件格式中是一个常量池索引指向 UTF8 字符串JVM 用它来识别属性类型自定义属性名应避免与已登记的标准属性名冲突。isUnknown()返回false这是向 ASM 表明本类不是未知属性而是可被 ASM 识别、可解码的自定义属性类型。这也是继承Attribute时必须重写的方法。read方法对这一类型的属性的原始内容进行解码。参数中的off是属性值在ClassReader所读字节数组中的偏移量buf是用于读取 UTF8 字符串的临时字符缓冲。这里调用cr.readUTF8(off, buf)直接从偏移处读出 UTF8 字符串——这也印证了原始内容中short值引用常量池 UTF8 字符串的结构设计。write方法执行逆操作即重新编码。cw.newUTF8(comment)在ClassWriter的常量池中创建或复用一个 UTF8 常量并返回其索引new ByteVector().putShort(...)将该索引以short形式写入属性字节数组。注意read方法必须返回一个新的属性实例。ASM 会为每个被识别的该类型属性分别调用一次read并收集返回的新实例因此不能在read中返回this或复用已有实例。注册原型实例仅仅定义子类还不够。ClassReader需要知道遇到名为Comment的属性时应该用哪个类去解码。为此必须在调用accept时传入该类型的一个原型实例ClassReader cr ...; ClassVisitor cv ...; cr.accept(cv, new Attribute[] { new CommentAttribute() }, 0);accept的第二个参数是一个Attribute数组里面放的是原型实例原型中的字段值无关紧要解码时会被read生成的新实例覆盖。accept的第三个参数是int类型的解析标志此处为 0表示默认解析行为。完成注册后类文件中的每一个Comment属性都将被识别并为它们中的每一个都创建一个CommentAttribute实例——这些实例携带解码后的comment值可以在你的ClassVisitor的visitAttribute回调中直接使用。而其他未被识别的属性仍会用普通的Attribute实例表示继续走原样复制的默认路径。属性与注释什么时候该用自定义属性JVM 类文件中的注释机制 可以看作属性的进化形态类、字段、方法和方法参数注释只要保留策略不是RetentionPolicy.SOURCE就会被存储在编译后的类中ASM为其提供了独立的AnnotationVisitor访问器体系visitAnnotation、visitEnum、visitArray等ASMifier 甚至可以直接生成构造注释类的 ASM 代码。两者对比实践中的选择标准可以归纳为能用注释解决的问题优先用注释注释有源代码语法、编译器检查、javac与反射 API 的统一支持AnnotationVisitor提供类型安全的嵌套结构访问开发成本远低于属性。必须处理非标准属性时才使用Attribute典型场景包括——读取第三方库生成的、带有私有属性的类文件实现 JVM 规范之外、未被 ASM 内置识别的标准属性如 ASM 自身尚未支持的较新规范属性或者你确实需要向类文件中写入不透明的二进制附加信息。三处访问入口类、字段、方法的 visitAttribute由于属性可以挂在类、字段、方法三个层级上ASM 在三个访问器抽象类中分别定义了visitAttribute(Attribute attr)方法参见 ClassVisitor 与 MethodVisitor 的源码结构访问器方法触发时机ClassVisitorvisitAttribute(Attribute attr)在visit之后、visitInnerClass/visitField/visitMethod之前FieldVisitorvisitAttribute(Attribute attr)在字段的visitAnnotation之后、visitEnd之前MethodVisitorvisitAttribute(Attribute attr)在方法的注释与参数注释之后、visitCode之前事件模型的调用顺序约束见 2.2 接口和组件visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )* ( visitInnerClass | visitField | visitMethod )* visitEnd方法层级的顺序约束见 3.2 接口和组件visitAnnotationDefault? ( visitAnnotation | visitParameterAnnotation | visitAttribute )* ( visitCode ... visitMaxs )? visitEnd因此在编写类适配器时若要读取自定义属性并据此调整转换逻辑需要重写对应层级的visitAttribute若要新增属性则需要遵循上述调用顺序将visitAttribute调用插入到正确的时间点。使用工具验证自定义属性在开发Attribute子类时2.3 工具 一章提供的调试工具同样适用TraceClassVisitor生成所访问类的文本表示。用它替代或包裹ClassWriter可以直观地看到自定义属性是否被正确解析、read/write往返后内容是否一致。CheckClassAdapter验证对visitAttribute等方法的调用顺序与参数是否合法在属性接入事件链出现顺序错误时提前抛出异常避免产出被 JVM 验证器拒绝的类文件。ASMifier如果你想知道如何用 ASM 生成某个带属性的类先写 Java 源码、用javac编译再用 ASMifier 访问编译产物即可得到对应的 ASM 生成代码其中就包括visitAttribute的调用写法。小结围绕 A.3 属性本文梳理了完整的技术闭环属性是 JVM 类文件格式官方的可扩展机制可挂在类、字段、方法三层ClassReader默认把未知属性封装为不透明的Attribute实例通过visitAttribute交给访问链ClassWriter原样复制其原始字节原样复制只有在启用 2.2.4 节 的常量池复制优化时才是安全的否则新常量池会让属性内索引失效、损坏类文件要读写自定义属性需定义Attribute子类并重写read/write/isUnknown再通过ClassReader.accept(cv, new Attribute[]{...}, 0)注册原型实例Java 5 注释机制出现后能用注释解决的场景优先用注释自定义属性只用于处理非标准属性或二进制附加信息的场景。CodeGuide 仓库中 asm-document 目录还包含完整的属性、注释、方法、后向兼容等章节如 A.4 规则、4.2 注释、A.5 性能结合 ASM 字节码编程实战系列 中的 JavaAgent 与字节码插桩案例Javassist 篇、Byte-buddy 篇、ASM 篇阅读可以形成从原理到落地的完整知识链路。赞分享文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载相关推荐深度解析 NumPy 文档构建autosummary attribute 模板与类属性文档页生成机制深度解析 NumPy 文档构建autosummary attribute 模板与类属性文档页生成机制 导读 Sphinx 的 autosummary 扩展是科学计算数据分析Cherry Studio 完整教程3 步接入 300 AI 模型桌面端一站式搞定Cherry Studio 完整教程3 步接入 300 AI 模型桌面端一站式搞定 你是不是也遇到过这种场面OpenAI 的 key 躺在浏览器书签里AI 应用大模型桌面应用本地部署RAGPHPStan 错误标识符解析attribute.trait——Trait 不能用作属性Attribute类PHPStan 错误标识符解析attribute.trait——Trait 不能用作属性Attribute类 本文以 PHPStan 官方错误标识符文档开发工具代码质量静态分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号