1. 程式人生 > 其它 >Spring原始碼之Bean元件掃描解析類ClassPathBeanDefinitionScanner

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.2ClassPathBeanDefinitionScanner.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"));
        }
    }