美文网首页
Spring源码分析之包扫描

Spring源码分析之包扫描

作者: 不迷烟火 | 来源:发表于2019-02-01 14:39 被阅读0次

一.基本知识点

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。

相关文章

网友评论

      本文标题:Spring源码分析之包扫描

      本文链接:https://www.haomeiwen.com/subject/kjldsqtx.html