什么是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模式
ClassReader : 我现在要解析一个复杂结构的类文件了啊, 每当我解析好一点东西,
我都会通知你来处理。
ClassVisistor : 你怎么通知我?
ClassReader : 当然是回调你的方法啊, 比如说当我开始解析一个方法时,
我就会回调你的visistMethod() , 把相关数据给你发过去, 你就可以处理了
ClassVisitor : 明白!但是当我处理完了,比如修改了字节码, 怎么写回去呢?
ClassReader : 你可以创建一个ClassWriter 对象, 每次处理完以后,再调用同样的方法,
例如visitMethod(), 这样ClassWriter 就知道你的修改了, 它负责写回去。
在Spring中的应用
类图
调用层次
首先会调用ClassMetadataReadingVisitor类的visit方法——>
调用AnnotationMetadataReadingVisitor类的visitAnnotation方法
—–>调用AnnotationAttributesReadingVisitor类的visit方法。
—>调用AnnotationAttributesReadingVisitorvisitEnd方法—–> 最后获取注解中的内容
关键代码
- 测试代码
@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"));
}
- 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]);
}
}
- 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);
}
4. AnnotationAttributesReadingVisitor
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);
}
对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;
}
源码地址:https://github.com/XWxiaowei/spring-learn/tree/testcase-v5-auto-scan-1/liu-spring-demo