从零开始造Spring04---补充之ASM的原理以及在Spring中的应用

举报
码农飞哥 发表于 2021/05/29 13:28:41 2021/05/29
【摘要】 什么是ASM ASM 是一个可以操作Java 字节码的框架。可以读取/修改class中的字节码。ASM可以直接产生二进制class文件,也可以在类被加载Java虚拟机之前动态改变类行为,Java class被存储在严格格式定义的.class文件里,这些文件拥有足够的元数据来解析勒种的所有元素:类名称, 方法,属性以及Java字节码(指令)。ASM从类文件中读入信息后,...

什么是ASM

ASM 是一个可以操作Java 字节码的框架。可以读取/修改class中的字节码。ASM可以直接产生二进制class文件,也可以在类被加载Java虚拟机之前动态改变类行为,Java class被存储在严格格式定义的.class文件里,这些文件拥有足够的元数据来解析勒种的所有元素:类名称, 方法,属性以及Java字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
与 BCEL 和 SERL 不同,ASM 提供了更为现代的编程模型。对于 ASM 来说,Java class 被描述为一棵树;使用 “Visitor” 模式遍历整个二进制结构;事件驱动的处理方式使得用户只需要关注于对其编程有意义的部分,而不必了解 Java 类文件格式的所有细节:ASM 框架提供了默认的 “response taker”处理这一切。

说明

这是学习刘欣老师《从零开始造Spring》课程的学习笔记

ASM的Visitor模式

ASM的Visitor模式

ClassReader : 我现在要解析一个复杂结构的类文件了啊, 每当我解析好一点东西,
我都会通知你来处理。

ClassVisistor : 你怎么通知我?

ClassReader : 当然是回调你的方法啊, 比如说当我开始解析一个方法时,
我就会回调你的visistMethod() , 把相关数据给你发过去, 你就可以处理了

ClassVisitor : 明白!但是当我处理完了,比如修改了字节码, 怎么写回去呢?

ClassReader : 你可以创建一个ClassWriter 对象, 每次处理完以后,再调用同样的方法,
例如visitMethod(), 这样ClassWriter 就知道你的修改了, 它负责写回去。

在Spring中的应用

类图

这里写图片描述

调用层次

首先会调用ClassMetadataReadingVisitor类的visit方法——>
调用AnnotationMetadataReadingVisitor类的visitAnnotation方法
—–>调用AnnotationAttributesReadingVisitor类的visit方法。
—>调用AnnotationAttributesReadingVisitorvisitEnd方法—–> 最后获取注解中的内容

关键代码

  1. 测试代码
   @Test public void  testGetAnnonation() throws IOException { ClassPathResource resource = new ClassPathResource("com/jay/spring/service/v4/PetStoreService.class"); ClassReader reader = new ClassReader(resource.getInputStream()); AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(); reader.accept(visitor, ClassReader.SKIP_DEBUG); String annotation = "com.jay.spring.stereotype.Component"; Assert.assertTrue(visitor.hasAnnotation(annotation)); AnnotationAttributes attributes = visitor.getAnnotationAttributes(annotation); Assert.assertEquals("petStoreService", attributes.get("value")); }
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  1. ClassMetadataReadingVisitor类
   public void visit(int version, int access, String name, String signature, String supername, String[] interfaces) { this.className = ClassUtils.convertResourcePathToClassName(name); this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0); this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0); this.isFinal = ((access & Opcodes.ACC_FINAL) != 0); if (supername != null) { this.superClassName = ClassUtils.convertResourcePathToClassName(supername); } this.interfaces = new String[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { this.interfaces[i] = ClassUtils.convertResourcePathToClassName(interfaces[i]); } }
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  1. AnnotationMetadataReadingVisitor类
   @Override public AnnotationVisitor visitAnnotation(final String desc, boolean visible) { String className = Type.getType(desc).getClassName(); this.annotationSet.add(className); return new AnnotationAttributesReadingVisitor(className, this.attributeMap); }
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
4. AnnotationAttributesReadingVisitor 

  
 
  • 1
public class AnnotationAttributesReadingVisitor extends AnnotationVisitor { private final String annotationType; private final Map<String, AnnotationAttributes> attributesMap; AnnotationAttributes attributes = new AnnotationAttributes(); public AnnotationAttributesReadingVisitor( String annotationType, Map<String, AnnotationAttributes> attributesMap) { super(SpringAsmInfo.ASM_VERSION); this.annotationType = annotationType; this.attributesMap = attributesMap; } @Override public final void visitEnd() { this.attributesMap.put(this.annotationType, this.attributes); } @Override public void visit(String attributeName, Object attributeValue) { this.attributes.put(attributeName, attributeValue); }
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

对asm实现的封装

类图

这里写图片描述

关键代码

public class SimpleMetadataReader implements MetadataReader { private final Resource resource; private final ClassMetadata classMetadata; private final AnnotationMetadata annotationMetadata; public SimpleMetadataReader(Resource resource) throws IOException { InputStream inputStream = new BufferedInputStream(resource.getInputStream()); ClassReader classReader; try { classReader = new ClassReader(inputStream); } finally { inputStream.close(); } AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(); classReader.accept(visitor, ClassReader.SKIP_DEBUG); this.annotationMetadata = visitor; this.classMetadata = visitor; this.resource = resource; } @Override public Resource getResource() { return this.resource; } @Override public ClassMetadata getClassMetadata() { return this.classMetadata; } @Override public AnnotationMetadata getAnnotationMetadata() { return this.annotationMetadata; }
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

源码地址

文章来源: feige.blog.csdn.net,作者:码农飞哥,版权归原作者所有,如需转载,请联系作者。

原文链接:feige.blog.csdn.net/article/details/81071452

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。