美文网首页
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