git地址:
https://github.com/lixiao853771701/springBootAsmDemo
参考的spring加载类的代码
spring的类 SimpleMetadataReader中
构造方法
SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(classLoader);
getClassReader(resource).accept(visitor, PARSING_OPTIONS);
this.resource = resource;
this.annotationMetadata = visitor.getMetadata();
}
其中这一行 getClassReader(resource).accept(visitor, PARSING_OPTIONS); 就是利用了ASM技术读取
getClassReader(resource)点进去
private static ClassReader getClassReader(Resource resource) throws IOException {
try (InputStream is = resource.getInputStream()) {
try {
return new ClassReader(is);
}
catch (IllegalArgumentException ex) {
throw new org.springframework.core.NestedIOException("ASM ClassReader failed to parse class file - " +
"probably due to a new Java class file version that isn't supported yet: " + resource, ex);
}
}
}
以下是扒下来的代码:
MergedAnnotationReadingVisitor
public class MergedAnnotationReadingVisitor<A extends Annotation> extends AnnotationVisitor {
@Nullable
private final ClassLoader classLoader;
@Nullable
private final Object source;
private final Class<A> annotationType;
private final Consumer<MergedAnnotation<A>> consumer;
private final Map<String, Object> attributes = new LinkedHashMap<>(4);
public MergedAnnotationReadingVisitor(@Nullable ClassLoader classLoader, @Nullable Object source,
Class<A> annotationType, Consumer<MergedAnnotation<A>> consumer) {
super(SpringAsmInfo.ASM_VERSION);
this.classLoader = classLoader;
this.source = source;
this.annotationType = annotationType;
this.consumer = consumer;
}
@Override
public void visit(String name, Object value) {
if (value instanceof Type) {
value = ((Type) value).getClassName();
}
this.attributes.put(name, value);
}
@Override
public void visitEnum(String name, String descriptor, String value) {
visitEnum(descriptor, value, enumValue -> this.attributes.put(name, enumValue));
}
@Override
@Nullable
public AnnotationVisitor visitAnnotation(String name, String descriptor) {
return visitAnnotation(descriptor, annotation -> this.attributes.put(name, annotation));
}
@Override
public AnnotationVisitor visitArray(String name) {
return new MergedAnnotationReadingVisitor.ArrayVisitor(value -> this.attributes.put(name, value));
}
@Override
public void visitEnd() {
MergedAnnotation<A> annotation = MergedAnnotation.of(
this.classLoader, this.source, this.annotationType, this.attributes);
this.consumer.accept(annotation);
}
@SuppressWarnings("unchecked")
public <E extends Enum<E>> void visitEnum(String descriptor, String value, Consumer<E> consumer) {
String className = Type.getType(descriptor).getClassName();
Class<E> type = (Class<E>) ClassUtils.resolveClassName(className, this.classLoader);
consumer.accept(Enum.valueOf(type, value));
}
@SuppressWarnings("unchecked")
@Nullable
private <T extends Annotation> AnnotationVisitor visitAnnotation(
String descriptor, Consumer<MergedAnnotation<T>> consumer) {
String className = Type.getType(descriptor).getClassName();
if (AnnotationFilter.PLAIN.matches(className)) {
return null;
}
Class<T> type = (Class<T>) ClassUtils.resolveClassName(className, this.classLoader);
return new MergedAnnotationReadingVisitor<>(this.classLoader, this.source, type, consumer);
}
@SuppressWarnings("unchecked")
@Nullable
static <A extends Annotation> AnnotationVisitor get(@Nullable ClassLoader classLoader,
@Nullable Object source, String descriptor, boolean visible,
Consumer<MergedAnnotation<A>> consumer) {
if (!visible) {
return null;
}
String typeName = Type.getType(descriptor).getClassName();
if (AnnotationFilter.PLAIN.matches(typeName)) {
return null;
}
try {
Class<A> annotationType = (Class<A>) ClassUtils.forName(typeName, classLoader);
return new MergedAnnotationReadingVisitor<>(classLoader, source, annotationType, consumer);
}
catch (ClassNotFoundException | LinkageError ex) {
return null;
}
}
/**
* {@link AnnotationVisitor} to deal with array attributes.
*/
private class ArrayVisitor extends AnnotationVisitor {
private final List<Object> elements = new ArrayList<>();
private final Consumer<Object[]> consumer;
ArrayVisitor(Consumer<Object[]> consumer) {
super(SpringAsmInfo.ASM_VERSION);
this.consumer = consumer;
}
@Override
public void visit(String name, Object value) {
if (value instanceof Type) {
value = ((Type) value).getClassName();
}
this.elements.add(value);
}
@Override
public void visitEnum(String name, String descriptor, String value) {
MergedAnnotationReadingVisitor.this.visitEnum(descriptor, value, this.elements::add);
}
@Override
@Nullable
public AnnotationVisitor visitAnnotation(String name, String descriptor) {
return MergedAnnotationReadingVisitor.this.visitAnnotation(descriptor, this.elements::add);
}
@Override
public void visitEnd() {
Class<?> componentType = getComponentType();
Object[] array = (Object[]) Array.newInstance(componentType, this.elements.size());
this.consumer.accept(this.elements.toArray(array));
}
private Class<?> getComponentType() {
if (this.elements.isEmpty()) {
return Object.class;
}
Object firstElement = this.elements.get(0);
if (firstElement instanceof Enum) {
return ((Enum<?>) firstElement).getDeclaringClass();
}
return firstElement.getClass();
}
}
}
SimpleAnnotationMetadata
public class SimpleAnnotationMetadata implements AnnotationMetadata {
private final String className;
private final int access;
@Nullable
private final String enclosingClassName;
@Nullable
private final String superClassName;
private final boolean independentInnerClass;
private final String[] interfaceNames;
private final String[] memberClassNames;
private final MethodMetadata[] annotatedMethods;
private final MergedAnnotations annotations;
@Nullable
private Set<String> annotationTypes;
SimpleAnnotationMetadata(String className, int access, @Nullable String enclosingClassName,
@Nullable String superClassName, boolean independentInnerClass, String[] interfaceNames,
String[] memberClassNames, MethodMetadata[] annotatedMethods, MergedAnnotations annotations) {
this.className = className;
this.access = access;
this.enclosingClassName = enclosingClassName;
this.superClassName = superClassName;
this.independentInnerClass = independentInnerClass;
this.interfaceNames = interfaceNames;
this.memberClassNames = memberClassNames;
this.annotatedMethods = annotatedMethods;
this.annotations = annotations;
}
@Override
public String getClassName() {
return this.className;
}
@Override
public boolean isInterface() {
return (this.access & Opcodes.ACC_INTERFACE) != 0;
}
@Override
public boolean isAnnotation() {
return (this.access & Opcodes.ACC_ANNOTATION) != 0;
}
@Override
public boolean isAbstract() {
return (this.access & Opcodes.ACC_ABSTRACT) != 0;
}
@Override
public boolean isFinal() {
return (this.access & Opcodes.ACC_FINAL) != 0;
}
@Override
public boolean isIndependent() {
return (this.enclosingClassName == null || this.independentInnerClass);
}
@Override
@Nullable
public String getEnclosingClassName() {
return this.enclosingClassName;
}
@Override
@Nullable
public String getSuperClassName() {
return this.superClassName;
}
@Override
public String[] getInterfaceNames() {
return this.interfaceNames.clone();
}
@Override
public String[] getMemberClassNames() {
return this.memberClassNames.clone();
}
@Override
public MergedAnnotations getAnnotations() {
return this.annotations;
}
@Override
public Set<String> getAnnotationTypes() {
Set<String> annotationTypes = this.annotationTypes;
if (annotationTypes == null) {
annotationTypes = Collections.unmodifiableSet(
AnnotationMetadata.super.getAnnotationTypes());
this.annotationTypes = annotationTypes;
}
return annotationTypes;
}
@Override
public Set<MethodMetadata> getAnnotatedMethods(String annotationName) {
Set<MethodMetadata> annotatedMethods = null;
for (MethodMetadata annotatedMethod : this.annotatedMethods) {
if (annotatedMethod.isAnnotated(annotationName)) {
if (annotatedMethods == null) {
annotatedMethods = new LinkedHashSet<>(4);
}
annotatedMethods.add(annotatedMethod);
}
}
return (annotatedMethods != null ? annotatedMethods : Collections.emptySet());
}
@Override
public boolean equals(@Nullable Object obj) {
// return ((this == obj) || ((obj instanceof org.springframework.core.type.classreading.SimpleAnnotationMetadata) &&
// this.className.equals(((org.springframework.core.type.classreading.SimpleAnnotationMetadata) obj).className)));
return false;
}
@Override
public int hashCode() {
return this.className.hashCode();
}
@Override
public String toString() {
return this.className;
}
}
SimpleAnnotationMetadataReadingVisitor
public class SimpleAnnotationMetadataReadingVisitor extends ClassVisitor {
@Nullable
private final ClassLoader classLoader;
private String className = "";
private int access;
@Nullable
private String superClassName;
private String[] interfaceNames = new String[0];
@Nullable
private String enclosingClassName;
private boolean independentInnerClass;
private Set<String> memberClassNames = new LinkedHashSet<>(4);
private List<MergedAnnotation<?>> annotations = new ArrayList<>();
private List<SimpleMethodMetadata> annotatedMethods = new ArrayList<>();
@Nullable
private SimpleAnnotationMetadata metadata;
@Nullable
private Source source;
SimpleAnnotationMetadataReadingVisitor(@Nullable ClassLoader classLoader) {
super(SpringAsmInfo.ASM_VERSION);
this.classLoader = classLoader;
}
@Override
public void visit(int version, int access, String name, String signature,
@Nullable String supername, String[] interfaces) {
this.className = toClassName(name);
this.access = access;
if (supername != null && !isInterface(access)) {
this.superClassName = toClassName(supername);
}
this.interfaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
this.interfaceNames[i] = toClassName(interfaces[i]);
}
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
this.enclosingClassName = toClassName(owner);
}
@Override
public void visitInnerClass(String name, @Nullable String outerName, String innerName, int access) {
if (outerName != null) {
String className = toClassName(name);
String outerClassName = toClassName(outerName);
if (this.className.equals(className)) {
this.enclosingClassName = outerClassName;
this.independentInnerClass = ((access & Opcodes.ACC_STATIC) != 0);
}
else if (this.className.equals(outerClassName)) {
this.memberClassNames.add(className);
}
}
}
@Override
@Nullable
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
return MergedAnnotationReadingVisitor.get(this.classLoader, getSource(),
descriptor, visible, this.annotations::add);
}
@Override
@Nullable
public MethodVisitor visitMethod(
int access, String name, String descriptor, String signature, String[] exceptions) {
// Skip bridge methods - we're only interested in original
// annotation-defining user methods. On JDK 8, we'd otherwise run into
// double detection of the same annotated method...
if (isBridge(access)) {
return null;
}
return new SimpleMethodMetadataReadingVisitor(this.classLoader, this.className,
access, name, descriptor, this.annotatedMethods::add);
}
@Override
public void visitEnd() {
String[] memberClassNames = StringUtils.toStringArray(this.memberClassNames);
MethodMetadata[] annotatedMethods = this.annotatedMethods.toArray(new MethodMetadata[0]);
MergedAnnotations annotations = MergedAnnotations.of(this.annotations);
this.metadata = new SimpleAnnotationMetadata(this.className, this.access,
this.enclosingClassName, this.superClassName, this.independentInnerClass,
this.interfaceNames, memberClassNames, annotatedMethods, annotations);
}
public SimpleAnnotationMetadata getMetadata() {
Assert.state(this.metadata != null, "AnnotationMetadata not initialized");
return this.metadata;
}
private SimpleAnnotationMetadataReadingVisitor.Source getSource() {
SimpleAnnotationMetadataReadingVisitor.Source source = this.source;
if (source == null) {
source = new SimpleAnnotationMetadataReadingVisitor.Source(this.className);
this.source = source;
}
return source;
}
private String toClassName(String name) {
return ClassUtils.convertResourcePathToClassName(name);
}
private boolean isBridge(int access) {
return (access & Opcodes.ACC_BRIDGE) != 0;
}
private boolean isInterface(int access) {
return (access & Opcodes.ACC_INTERFACE) != 0;
}
/**
* {@link MergedAnnotation} source.
*/
private static final class Source {
private final String className;
Source(String className) {
this.className = className;
}
@Override
public int hashCode() {
return this.className.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return this.className.equals(((SimpleAnnotationMetadataReadingVisitor.Source) obj).className);
}
@Override
public String toString() {
return this.className;
}
}
}
SimpleMethodMetadata
public class SimpleMethodMetadata implements MethodMetadata {
private final String methodName;
private final int access;
private final String declaringClassName;
private final String returnTypeName;
// The source implements equals(), hashCode(), and toString() for the underlying method.
private final Object source;
private final MergedAnnotations annotations;
SimpleMethodMetadata(String methodName, int access, String declaringClassName,
String returnTypeName, Object source, MergedAnnotations annotations) {
this.methodName = methodName;
this.access = access;
this.declaringClassName = declaringClassName;
this.returnTypeName = returnTypeName;
this.source = source;
this.annotations = annotations;
}
@Override
public String getMethodName() {
return this.methodName;
}
@Override
public String getDeclaringClassName() {
return this.declaringClassName;
}
@Override
public String getReturnTypeName() {
return this.returnTypeName;
}
@Override
public boolean isAbstract() {
return (this.access & Opcodes.ACC_ABSTRACT) != 0;
}
@Override
public boolean isStatic() {
return (this.access & Opcodes.ACC_STATIC) != 0;
}
@Override
public boolean isFinal() {
return (this.access & Opcodes.ACC_FINAL) != 0;
}
@Override
public boolean isOverridable() {
return !isStatic() && !isFinal() && !isPrivate();
}
private boolean isPrivate() {
return (this.access & Opcodes.ACC_PRIVATE) != 0;
}
@Override
public MergedAnnotations getAnnotations() {
return this.annotations;
}
@Override
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof SimpleMethodMetadata) &&
this.source.equals(((SimpleMethodMetadata) obj).source)));
}
@Override
public int hashCode() {
return this.source.hashCode();
}
@Override
public String toString() {
return this.source.toString();
}
}
SimpleMethodMetadataReadingVisitor
public class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
@Nullable
private final ClassLoader classLoader;
private final String declaringClassName;
private final int access;
private final String methodName;
private final String descriptor;
private final List<MergedAnnotation<?>> annotations = new ArrayList<>(4);
private final Consumer<SimpleMethodMetadata> consumer;
@Nullable
private SimpleMethodMetadataReadingVisitor.Source source;
SimpleMethodMetadataReadingVisitor(@Nullable ClassLoader classLoader, String declaringClassName,
int access, String methodName, String descriptor, Consumer<SimpleMethodMetadata> consumer) {
super(SpringAsmInfo.ASM_VERSION);
this.classLoader = classLoader;
this.declaringClassName = declaringClassName;
this.access = access;
this.methodName = methodName;
this.descriptor = descriptor;
this.consumer = consumer;
}
@Override
@Nullable
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
return MergedAnnotationReadingVisitor.get(this.classLoader, getSource(),
descriptor, visible, this.annotations::add);
}
@Override
public void visitEnd() {
if (!this.annotations.isEmpty()) {
String returnTypeName = Type.getReturnType(this.descriptor).getClassName();
MergedAnnotations annotations = MergedAnnotations.of(this.annotations);
SimpleMethodMetadata metadata = new SimpleMethodMetadata(this.methodName, this.access,
this.declaringClassName, returnTypeName, getSource(), annotations);
this.consumer.accept(metadata);
}
}
private Object getSource() {
SimpleMethodMetadataReadingVisitor.Source source = this.source;
if (source == null) {
source = new SimpleMethodMetadataReadingVisitor.Source(this.declaringClassName, this.methodName, this.descriptor);
this.source = source;
}
return source;
}
/**
* {@link MergedAnnotation} source.
*/
static final class Source {
private final String declaringClassName;
private final String methodName;
private final String descriptor;
@Nullable
private String toStringValue;
Source(String declaringClassName, String methodName, String descriptor) {
this.declaringClassName = declaringClassName;
this.methodName = methodName;
this.descriptor = descriptor;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + this.declaringClassName.hashCode();
result = 31 * result + this.methodName.hashCode();
result = 31 * result + this.descriptor.hashCode();
return result;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
SimpleMethodMetadataReadingVisitor.Source otherSource = (SimpleMethodMetadataReadingVisitor.Source) other;
return (this.declaringClassName.equals(otherSource.declaringClassName) &&
this.methodName.equals(otherSource.methodName) && this.descriptor.equals(otherSource.descriptor));
}
@Override
public String toString() {
String value = this.toStringValue;
if (value == null) {
StringBuilder builder = new StringBuilder();
builder.append(this.declaringClassName);
builder.append('.');
builder.append(this.methodName);
Type[] argumentTypes = Type.getArgumentTypes(this.descriptor);
builder.append('(');
for (int i = 0; i < argumentTypes.length; i++) {
if (i != 0) {
builder.append(',');
}
builder.append(argumentTypes[i].getClassName());
}
builder.append(')');
value = builder.toString();
this.toStringValue = value;
}
return value;
}
}
}
Test
public class Test {
public static void main(String[] args) throws Exception {
InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("com\\xx\\xxx\\Xxxx.class");
ClassReader classReader = new ClassReader(resourceAsStream);
SimpleAnnotationMetadataReadingVisitor visitor = new SimpleAnnotationMetadataReadingVisitor(ClassLoader.getSystemClassLoader());
classReader.accept(visitor, 2);
System.out.println();
}
}