一.基本知識點(diǎn)
1.Metadata
元數(shù)據(jù)
基本概念:
定義:元數(shù)據(jù)(Metadata)侈咕,又稱中介數(shù)據(jù)公罕、中繼數(shù)據(jù),為描述數(shù)據(jù)的數(shù)據(jù),主要是描述數(shù)據(jù)屬性的信息耀销。
3699854-40620b7696251879.png
作用:
就是獲取類的相關(guān)屬性和信息
獲取方法:( AnnotationMetadata)
MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(SpringbootApplication.class.getName());
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
底層獲取原理(通過asm獲取類的各個相關(guān)信息)(getMetadataReader)
// 封裝成資源文件
Resource resource = new DefaultResourceLoader().getResource("classpath:com/example/springboot/SpringbootApplication.class");
InputStream is = new BufferedInputStream(resource.getInputStream());
// org.springframework.asm.ClassReader 獲取類的相關(guān)信息
ClassReader classReader = new ClassReader(resource.getInputStream());
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(SpringbootApplication.class.getClassLoader());
// AnnotationMetadataReadingVisitor(可看作是AnnotationMetadata)根據(jù)類的相關(guān)信息封裝成Spring所需的類的相關(guān)信息
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");
返回結(jié)果:
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) {
// 相當(dāng)于獲取(AnnotationMetadata)
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//1.重點(diǎn)
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
//2.重點(diǎn)
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
}
}
isCandidateComponent方法
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
// 默認(rèn)為空
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 默認(rèn)有(見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(當(dāng)前類的注解)(annotationSet )
return metadata.hasAnnotation(this.annotationType.getName()) ||
// metaAnnotationMap(當(dāng)前類的注解以及當(dāng)前類的注解的派生注解)
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
metadata.hasAnnotation
:例如如果當(dāng)前類上的注解為@Service,那么元注解的annotationSet屬性則為Service熊尉,不包含默認(rèn)過濾器中的@Component和@named條件之一罐柳,返回false。
metadata.hasMetaAnnotation
:例如如果當(dāng)前類上的注解為@Service狰住,那么元注解的metaAnotationMap則有@Service和@Component(@Service是@Component的派生屬性)肮蛹,包含默認(rèn)過濾器的@Component條件,則為true。