源碼
MetadataReaderFactory
MetadataReaderFactory
是用于創建 MetadataReader
實例的工廠接口,支持通過類名或資源讀取類的元數據并可實現緩存優化。
類型 | 類/接口名 | 功能描述 | 是否需要加載類 | 訪問方式 |
---|---|---|---|---|
抽象接口 | AnnotatedTypeMetadata | 訪問某類型(類或方法)的注解信息 | 否 | 抽象,支持字節碼讀取 |
抽象接口 | AnnotationMetadata | 訪問某類的注解信息 | 否 | 抽象,支持字節碼讀取 |
抽象接口 | ClassMetadata | 訪問某類的基本元數據(類名、父類、接口等) | 否 | 抽象,支持字節碼讀取 |
抽象接口 | MethodMetadata | 訪問某方法的注解和方法簽名 | 否 | 抽象,支持字節碼讀取 |
反射實現 | StandardAnnotationMetadata | 基于反射訪問類注解元數據 | 是 | Java反射 |
反射實現 | StandardClassMetadata | 基于反射訪問類的基本元數據 | 是 | Java反射 |
反射實現 | StandardMethodMetadata | 基于反射訪問方法元數據 | 是 | Java反射 |
public interface MetadataReaderFactory {MetadataReader getMetadataReader(String className) throws IOException;MetadataReader getMetadataReader(Resource resource) throws IOException;
}
SimpleMetadataReaderFactory
SimpleMetadataReaderFactory
根據類名或資源路徑加載對應的 .class
文件,創建用于讀取類元數據的 MetadataReader
實例。
public class SimpleMetadataReaderFactory implements MetadataReaderFactory {private final ResourceLoader resourceLoader;public SimpleMetadataReaderFactory() {this.resourceLoader = new DefaultResourceLoader();}public SimpleMetadataReaderFactory(@Nullable ResourceLoader resourceLoader) {this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());}public SimpleMetadataReaderFactory(@Nullable ClassLoader classLoader) {this.resourceLoader = (classLoader != null ? new DefaultResourceLoader(classLoader) : new DefaultResourceLoader());}public final ResourceLoader getResourceLoader() {return this.resourceLoader;}@Overridepublic MetadataReader getMetadataReader(String className) throws IOException {try {// "classpath:" + ClassUtils.convertClassNameToResourcePath(className) + ".class"String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;Resource resource = this.resourceLoader.getResource(resourcePath);return getMetadataReader(resource);}catch (FileNotFoundException ex) {int lastDotIndex = className.lastIndexOf('.');if (lastDotIndex != -1) {String innerClassName =className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);if (innerClassResource.exists()) {return getMetadataReader(innerClassResource);}}throw ex;}}@Overridepublic MetadataReader getMetadataReader(Resource resource) throws IOException {return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());}
}
CachingMetadataReaderFactory
CachingMetadataReaderFactory
是 SimpleMetadataReaderFactory
的緩存增強版,針對每個 .class
文件資源緩存對應的 MetadataReader
實例,避免重復解析,提高讀取類元數據的效率,并支持緩存大小限制與線程安全訪問。
public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {public static final int DEFAULT_CACHE_LIMIT = 256;@Nullableprivate Map<Resource, MetadataReader> metadataReaderCache;public CachingMetadataReaderFactory() {super();setCacheLimit(DEFAULT_CACHE_LIMIT);}public CachingMetadataReaderFactory(@Nullable ClassLoader classLoader) {super(classLoader);setCacheLimit(DEFAULT_CACHE_LIMIT);}public CachingMetadataReaderFactory(@Nullable ResourceLoader resourceLoader) {super(resourceLoader);if (resourceLoader instanceof DefaultResourceLoader defaultResourceLoader) {this.metadataReaderCache = defaultResourceLoader.getResourceCache(MetadataReader.class);}else {setCacheLimit(DEFAULT_CACHE_LIMIT);}}public void setCacheLimit(int cacheLimit) {if (cacheLimit <= 0) {this.metadataReaderCache = null;}else if (this.metadataReaderCache instanceof LocalResourceCache localResourceCache) {localResourceCache.setCacheLimit(cacheLimit);}else {this.metadataReaderCache = new LocalResourceCache(cacheLimit);}}public int getCacheLimit() {if (this.metadataReaderCache instanceof LocalResourceCache localResourceCache) {return localResourceCache.getCacheLimit();}else {return (this.metadataReaderCache != null ? Integer.MAX_VALUE : 0);}}@Overridepublic MetadataReader getMetadataReader(Resource resource) throws IOException {if (this.metadataReaderCache instanceof ConcurrentMap) {MetadataReader metadataReader = this.metadataReaderCache.get(resource);if (metadataReader == null) {metadataReader = super.getMetadataReader(resource);this.metadataReaderCache.put(resource, metadataReader);}return metadataReader;}else if (this.metadataReaderCache != null) {synchronized (this.metadataReaderCache) {MetadataReader metadataReader = this.metadataReaderCache.get(resource);if (metadataReader == null) {metadataReader = super.getMetadataReader(resource);this.metadataReaderCache.put(resource, metadataReader);}return metadataReader;}}else {return super.getMetadataReader(resource);}}public void clearCache() {if (this.metadataReaderCache instanceof LocalResourceCache) {synchronized (this.metadataReaderCache) {this.metadataReaderCache.clear();}}else if (this.metadataReaderCache != null) {setCacheLimit(DEFAULT_CACHE_LIMIT);}}@SuppressWarnings("serial")private static class LocalResourceCache extends LinkedHashMap<Resource, MetadataReader> {private volatile int cacheLimit;public LocalResourceCache(int cacheLimit) {super(cacheLimit, 0.75f, true);this.cacheLimit = cacheLimit;}public void setCacheLimit(int cacheLimit) {this.cacheLimit = cacheLimit;}public int getCacheLimit() {return this.cacheLimit;}@Overrideprotected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {return size() > this.cacheLimit;}}
}
MetadataReader
MetadataReader
是一個用于讀取類文件元數據(包括類信息和注解信息)的簡單門面接口,常用于組件掃描過程中的類型過濾判斷。
public interface MetadataReader {Resource getResource();ClassMetadata getClassMetadata();AnnotationMetadata getAnnotationMetadata();
}
SimpleMetadataReader
final class SimpleMetadataReader implements MetadataReader {// 性能優化:不加載無用信息,加快 ClassReader 處理速度。// 避免類初始化:避免加載類體或觸發靜態初始化,保證掃描階段安全。// 只關注元數據:如類名、注解、父類、接口、方法簽名等,無需方法體邏輯。// 跳過類的調試信息、方法字節碼和幀信息,只保留元數據,從而提升類掃描效率。private static final int PARSING_OPTIONS = (ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);private final Resource resource;private final AnnotationMetadata annotationMetadata;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();}private static ClassReader getClassReader(Resource resource) throws IOException {try (InputStream is = resource.getInputStream()) {try {return new ClassReader(is);}catch (IllegalArgumentException ex) {throw new ClassFormatException("ASM ClassReader failed to parse class file - " +"probably due to a new Java class file version that is not supported yet. " +"Consider compiling with a lower '-target' or upgrade your framework version. " +"Affected class: " + resource, ex);}}}@Overridepublic Resource getResource() {return this.resource;}@Overridepublic ClassMetadata getClassMetadata() {return this.annotationMetadata;}@Overridepublic AnnotationMetadata getAnnotationMetadata() {return this.annotationMetadata;}}
SimpleAnnotationMetadataReadingVisitor
SimpleAnnotationMetadataReadingVisitor
是基于 ASM 的 ClassVisitor實現,用于讀取類的注解、方法、父類、接口等元信息,并構建 SimpleAnnotationMetadata。
final class SimpleAnnotationMetadataReadingVisitor extends ClassVisitor {@Nullableprivate final ClassLoader classLoader;// 當前類的全限定名private String className = "";// 類的訪問修飾符(如 public, abstract, interface)private int access;// 父類名稱(不包括 Object)@Nullableprivate String superClassName;// 若當前類是內部類,記錄其外部類名@Nullableprivate String enclosingClassName;// 是否是靜態內部類private boolean independentInnerClass;// 實現的接口集合private final Set<String> interfaceNames = new LinkedHashSet<>(4);// 當前類包含的成員類(如內部類)private final Set<String> memberClassNames = new LinkedHashSet<>(4);// 所有類級別的合并注解private final Set<MergedAnnotation<?>> annotations = new LinkedHashSet<>(4);// 所有非構造器、非橋方法的元數據private final Set<MethodMetadata> declaredMethods = new LinkedHashSet<>(4);@Nullableprivate SimpleAnnotationMetadata metadata;@Nullableprivate Source source;SimpleAnnotationMetadataReadingVisitor(@Nullable ClassLoader classLoader) {super(SpringAsmInfo.ASM_VERSION);this.classLoader = classLoader;}@Overridepublic 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);}for (String element : interfaces) {this.interfaceNames.add(toClassName(element));}}@Overridepublic void visitOuterClass(String owner, String name, String desc) {this.enclosingClassName = toClassName(owner);}@Overridepublic 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);}}}// 當掃描到類上的注解時,visitAnnotation 方法會創建一個 MergedAnnotationReadingVisitor 來讀取注解內容,并將其添加到注解集合中。@Override@Nullablepublic AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {return MergedAnnotationReadingVisitor.get(this.classLoader, getSource(),descriptor, visible, this.annotations::add);}// visitMethod 方法跳過構造方法和橋接方法,僅為普通用戶方法創建 SimpleMethodMetadataReadingVisitor,用于收集方法注解信息并添加到集合中。@Override@Nullablepublic MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {// Skip bridge methods and constructors - we're only interested in original user methods.if (isBridge(access) || name.equals("<init>")) {return null;}return new SimpleMethodMetadataReadingVisitor(this.classLoader, this.className,access, name, descriptor, this.declaredMethods::add);}// 在類字節碼掃描結束時,將收集的類名、訪問權限、父類、接口、內部類、方法和注解等信息封裝為 SimpleAnnotationMetadata 實例,完成類的注解元數據構建。@Overridepublic void visitEnd() {MergedAnnotations annotations = MergedAnnotations.of(this.annotations);this.metadata = new SimpleAnnotationMetadata(this.className, this.access,this.enclosingClassName, this.superClassName, this.independentInnerClass,this.interfaceNames, this.memberClassNames, this.declaredMethods, annotations);}public SimpleAnnotationMetadata getMetadata() {Assert.state(this.metadata != null, "AnnotationMetadata not initialized");return this.metadata;}private Source getSource() {Source source = this.source;if (source == null) {source = new 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;}}}
SimpleMethodMetadataReadingVisitor
SimpleMethodMetadataReadingVisitor
是基于 ASM 的 MethodVisitor 實現,用于讀取方法的訪問權限、簽名、注解等元數據,并將這些方法信息封裝成簡化的元數據對象供框架使用。
final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {@Nullableprivate 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;@Nullableprivate 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@Nullablepublic AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {return MergedAnnotationReadingVisitor.get(this.classLoader, getSource(),descriptor, visible, this.annotations::add);}@Overridepublic void visitEnd() {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() {Source source = this.source;if (source == null) {source = new 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;@Nullableprivate String toStringValue;Source(String declaringClassName, String methodName, String descriptor) {this.declaringClassName = declaringClassName;this.methodName = methodName;this.descriptor = descriptor;}}}
MergedAnnotationReadingVisitor
MergedAnnotationReadingVisitor
通過 ASM 訪問字節碼中的注解及其屬性,遞歸解析注解及嵌套注解,最終構建出 Spring 框架通用的 MergedAnnotation
元數據對象,便于框架高效統一地讀取和處理注解信息。
class MergedAnnotationReadingVisitor<A extends Annotation> extends AnnotationVisitor {@Nullableprivate final ClassLoader classLoader;@Nullableprivate 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;}@Overridepublic void visit(String name, Object value) {if (value instanceof Type type) {value = type.getClassName();}this.attributes.put(name, value);}@Overridepublic void visitEnum(String name, String descriptor, String value) {visitEnum(descriptor, value, enumValue -> this.attributes.put(name, enumValue));}@Override@Nullablepublic AnnotationVisitor visitAnnotation(String name, String descriptor) {return visitAnnotation(descriptor, annotation -> this.attributes.put(name, annotation));}@Overridepublic AnnotationVisitor visitArray(String name) {return new ArrayVisitor(value -> this.attributes.put(name, value));}@Overridepublic void visitEnd() {Map<String, Object> compactedAttributes = (this.attributes.isEmpty() ? Collections.emptyMap() : this.attributes);MergedAnnotation<A> annotation = MergedAnnotation.of(this.classLoader, this.source, this.annotationType, compactedAttributes);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")@Nullableprivate <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")@Nullablestatic <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;}@Overridepublic void visit(String name, Object value) {if (value instanceof Type type) {value = type.getClassName();}this.elements.add(value);}@Overridepublic void visitEnum(String name, String descriptor, String value) {MergedAnnotationReadingVisitor.this.visitEnum(descriptor, value, this.elements::add);}@Override@Nullablepublic AnnotationVisitor visitAnnotation(String name, String descriptor) {return MergedAnnotationReadingVisitor.this.visitAnnotation(descriptor, this.elements::add);}@Overridepublic 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<?> enumeration) {return enumeration.getDeclaringClass();}return firstElement.getClass();}}
}
TypeFilter
TypeFilter
是一個函數式接口,用于基于類的元數據判斷該類是否符合組件掃描條件。
@FunctionalInterface
public interface TypeFilter {boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException;
}
org.springframework.core.type.filter
是 spring core包中用于類路徑掃描過程中的類型過濾支持包,提供了多種 TypeFilter 實現,可按注解、父類、正則、AspectJ 表達式等條件篩選類。
類名 | 用途 | 特點 |
---|---|---|
TypeFilter | 過濾接口 | 核心接口,所有過濾器的基礎 |
AbstractClassTestingTypeFilter | 抽象類 | 提供 ClassMetadata 訪問 |
AbstractTypeHierarchyTraversingFilter | 抽象類 | 支持遞歸檢查父類和接口 |
AnnotationTypeFilter | 注解過濾 | 匹配指定注解,可配置是否繼承 |
AssignableTypeFilter | 父類/接口匹配 | 匹配指定類型的子類或實現類 |
RegexPatternTypeFilter | 類名正則 | 使用正則表達式匹配類名 |
AspectJTypeFilter | AspectJ 表達式匹配 | 功能強大,適合復雜匹配需求 |
例子
@Component
public class CustomConfig {@Beanpublic Object customObj() {return new Object();}
}
public class CustomTypeFilter implements TypeFilter {@Overridepublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {String className = metadataReader.getClassMetadata().getClassName();// 只對 CustomConfig 類進行打印(可以根據需要改成其他判斷)if (className.contains("CustomConfig")) {// 打印類上的所有注解MergedAnnotations classAnnotations = metadataReader.getAnnotationMetadata().getAnnotations();System.out.println("Class Annotations of " + className + ":");classAnnotations.stream().forEach(annotation -> {System.out.println(" - " + annotation.getType().getName());});// 打印方法上的所有注解System.out.println("Method Annotations:");for (MethodMetadata methodMetadata : metadataReader.getAnnotationMetadata().getDeclaredMethods()) {System.out.println(" Method: " + methodMetadata.getMethodName());MergedAnnotations methodAnnotations = methodMetadata.getAnnotations();methodAnnotations.stream().forEach(annotation -> {System.out.println(" - " + annotation.getType().getName());});}}// 根據實際需要返回 true 或 false,這里只是打印,返回 false 不影響掃描return false;}
}
@Configuration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = CustomTypeFilter.class))
public class Application {@Beanpublic CommandLineRunner commandLineRunner(ApplicationContext ctx) {return args -> ctx.getBean(CustomConfig.class);}public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
Class Annotations of xyz.idoly.demo.config.CustomConfig:- org.springframework.stereotype.Component- org.springframework.stereotype.Indexed
Method Annotations:Method: customObj- org.springframework.context.annotation.Bean