一.基本知识点
1.Metadata
元数据
基本概念:
定义:元数据(Metadata),又称中介数据、中继数据,为描述数据的数据,主要是描述数据属性的信息。
3699854-40620b7696251879.png作用:
就是获取类的相关属性和信息
获取方法:( AnnotationMetadata)
MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(SpringbootApplication.class.getName());
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
底层获取原理(通过asm获取类的各个相关信息)(getMetadataReader)
// 封装成资源文件
Resource resource = new DefaultResourceLoader().getResource("classpath:com/example/springboot/SpringbootApplication.class");
InputStream is = new BufferedInputStream(resource.getInputStream());
// org.springframework.asm.ClassReader 获取类的相关信息
ClassReader classReader = new ClassReader(resource.getInputStream());
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(SpringbootApplication.class.getClassLoader());
// AnnotationMetadataReadingVisitor(可看作是AnnotationMetadata)根据类的相关信息封装成Spring所需的类的相关信息
classReader.accept(visitor, ClassReader.SKIP_DEBUG);
示例
1548996754837.png
2.源码分析
核心方法:findCandidateComponents
ClassPathScanningCandidateComponentProvider.findCandidateComponents(String basePackage)
代码:
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
Set<BeanDefinition> candidateComponents = provider.findCandidateComponents("com.example.springboot");
返回结果:
1548997224165.png
findCandidateComponents方法:
// spring5.0开始 索引 开启的话生成文件META-INF/spring.components 后面加载直接从本地文件读取(一般不建议开启 spring.index.ignore=true)
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
scanCandidateComponents方法
// 获取包类的所有资源文件
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
// 相当于获取(AnnotationMetadata)
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//1.重点
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
//2.重点
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
}
}
isCandidateComponent方法
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 默认为空
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 默认有(见registerDefaultFilters方法)
//(new AnnotationTypeFilter(Component.class))
//new AnnotationTypeFilter(javax.inject.Named)
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
match方法
if (matchSelf(metadataReader)) {
return true;
}
protected boolean matchSelf(MetadataReader metadataReader) {
// 获取元注解
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
// AnnortationMetadata(当前类的注解)(annotationSet )
return metadata.hasAnnotation(this.annotationType.getName()) ||
// metaAnnotationMap(当前类的注解以及当前类的注解的派生注解)
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
metadata.hasAnnotation
:例如如果当前类上的注解为@Service,那么元注解的annotationSet属性则为Service,不包含默认过滤器中的@Component和@named条件之一,返回false。
metadata.hasMetaAnnotation
:例如如果当前类上的注解为@Service,那么元注解的metaAnotationMap则有@Service和@Component(@Service是@Component的派生属性),包含默认过滤器的@Component条件,则为true。
网友评论