Spring源码之Bean组件扫描解析类ClassPathBeanDefinitionScanner

1.前言

在Spring的使用中,我没会通过@Controller、@Service、@Repository、@Component组件标注在一个类上,告诉Spring此类为一个Bean组件类,交由Spring为我们创建类的实例和管理Bean组件相关的生命周期。 

Spring管理Bean组件大致分为两大阶段。

  第一阶段(解析):是将我们通过组件注解标注的类解析成Bean组件的定义对象,也就是对应的BeanDefinition对象,该对象用来描述每个组件的一些基本信息

  第二阶段(创建):获取所有解析后的BeanDefinition对象,根据其相关属性创建成最终的一个个实例对象,实例的创建过程也会出发组件生命周期相关的勾子函数

2.准备工作

Spring版本:2.2.13.RELEASE

说明:文中统一将被@Controller、@Service、@Repository、@Component标注的类称为组件类

源码中涉及的类

  • ClassPathBeanDefinitionScanner
  • ClassPathScanningCandidateComponentProvider

 

 

 3.源码流程分析

3.1流程入口方法 ClassPathBeanDefinitionScanner.scan

public int scan(String... basePackages) {
        // 获取此次组件扫描之前Spring容器中组件定义的数量
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

        // 根据包路径开始扫描包下的所有组件
        doScan(basePackages);

        // 是否开启注解驱动,主要针对@Autowird、@Configuration、@PostConstruct、@PreDestroy等注解的支持
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }
        // 返回此次扫描新增的组件数量
        return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
    }

3.2 ClassPathBeanDefinitionScanner.doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 扫描包不能为空
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        // 扫描后的组件集合
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
        // 循环所有包路径,依次进行扫描
        for (String basePackage : basePackages) {
            // 查找候选的组件集合
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            // 循环所有候选的组件定义信息
            for (BeanDefinition candidate : candidates) {
                /*
                    解析组件的作用域 singleton、prototype、request、session、global
                 */
                ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                candidate.setScope(scopeMetadata.getScopeName());
                // 生成组件的名称
                String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                // 如果为一个非注解标注的组件
                if (candidate instanceof AbstractBeanDefinition) {
                    postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                }
                // 如果为一个注解标注的组件
                if (candidate instanceof AnnotatedBeanDefinition) {
                    AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                }
                // 检查是否为候选的组件,如果是则将该组件的定义信息注册到Spring容器中
                if (checkCandidate(beanName, candidate)) {
                    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                    definitionHolder =
                            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                    beanDefinitions.add(definitionHolder);
                    registerBeanDefinition(definitionHolder, this.registry);
                }
            }
        }
        return beanDefinitions;
    }

3.3ClassPathScanningCandidateComponentProvider.findCandidateComponents

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        // 针对组件上的@Index注解的处理逻辑
        if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
            return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
        }
        else {
            return scanCandidateComponents(basePackage);
        }
    }
    
    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        // 组件定义集合,也是该方法的返回值
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            // 根据包路劲封装成Ant风格的全路径名称  org.spring -> classpath*:org/spring/**/*.class
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            // 调用资源模式解析器解析该路径下的所有类资源,这里的资源模式解析器用的是PathMatchingResourcePatternResolver,支持Ant路径模式
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            // 循环每一个类资源处理
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                try {
                    // 获取类资源上的元数据读取者
                    MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    // 是否为候选的组件,通过TypeFilter进行包含和排除过滤
                    if (isCandidateComponent(metadataReader)) {
                        // 封装成组件定义类BeanDefinition
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setSource(resource);
                        // 判断组件类是否是一个顶层类(非内部类)、静态内部类,非抽象类,包含@Lookup注解方法的抽象类
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            // 加入集合
                            candidates.add(sbd);
                        }
                        else {
                            if (debugEnabled) {
                                logger.debug("Ignored because not a concrete top-level class: " + resource);
                            }
                        }
                    }
                    else {
                        if (traceEnabled) {
                            logger.trace("Ignored because not matching any filter: " + resource);
                        }
                    }
                }
                catch (FileNotFoundException ex) {
                    if (traceEnabled) {
                        logger.trace("Ignored non-readable " + resource + ": " + ex.getMessage());
                    }
                }
                catch (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to read candidate component class: " + resource, ex);
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }

3.4AnnotationConfigUtils.processCommonDefinitionAnnotations

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
        /*
            处理@Lazy、@Primary、@DependsOn、@Role、@Description注解
         */
        AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
        if (lazy != null) {
            abd.setLazyInit(lazy.getBoolean("value"));
        }
        else if (abd.getMetadata() != metadata) {
            lazy = attributesFor(abd.getMetadata(), Lazy.class);
            if (lazy != null) {
                abd.setLazyInit(lazy.getBoolean("value"));
            }
        }

        if (metadata.isAnnotated(Primary.class.getName())) {
            abd.setPrimary(true);
        }
        AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
        if (dependsOn != null) {
            abd.setDependsOn(dependsOn.getStringArray("value"));
        }

        AnnotationAttributes role = attributesFor(metadata, Role.class);
        if (role != null) {
            abd.setRole(role.getNumber("value").intValue());
        }
        AnnotationAttributes description = attributesFor(metadata, Description.class);
        if (description != null) {
            abd.setDescription(description.getString("value"));
        }
    }

 

posted @ 2022-03-03 11:43  DreamPig丶  阅读(288)  评论(0编辑  收藏  举报