Spring IoC源碼學習:context:component-scan 節點詳解

目錄

Spring IoC源碼學習全系列

前言

正文

ComponentScanBeanDefinitionParser.parse

代碼塊1:configureScanner

代碼塊2:createScanner

代碼塊3:registerDefaultFilters

代碼塊4:parseTypeFilters

代碼塊5:doScan

代碼塊6:findCandidateComponents

代碼塊7:isCandidateComponent

代碼塊8:isCandidateComponent

代碼塊9:resolveScopeMetadata

代碼塊10:postProcessBeanDefinition

代碼塊11:processCommonDefinitionAnnotations

代碼塊12:checkCandidate

代碼塊13:applyScopedProxyMode

代碼塊14:createScopedProxy

代碼塊15:registerBeanDefinition

代碼塊16:registerComponents

代碼塊17:registerAnnotationConfigProcessors

代碼塊18:registerPostProcessor

總結

相關文章


Spring IoC源碼學習全系列

小白也看得懂的 Spring IoC 核心流程介紹

Spring IoC源碼學習:總覽

Spring IoC源碼學習:ApplicationContext 刷新前的配置

Spring IoC源碼學習:obtainFreshBeanFactory詳解

Spring IoC源碼學習:parseDefaultElement詳解

Spring IoC源碼學習:parseCustomElement詳解

Spring IoC源碼學習:obtainFreshBeanFactory詳解

Spring IoC源碼學習:invokeBeanFactoryPostProcessors詳解

Spring IoC源碼學習:registerBeanPostProcessors詳解

Spring IoC源碼學習:finishBeanFactoryInitialization詳解

Spring IoC源碼學習:getBean詳解

Spring IoC源碼學習:createBean詳解(上)

Spring IoC源碼學習:createBean詳解(下)

Spring IoC源碼學習:@Autowire 詳解

Spring IoC源碼學習:finishRefresh 詳解

 

前言

在 Spring IoC:parseCustomElement詳解 中,我們介紹了自定義命名空間節點解析的大部分內容,但是還剩下節點解析的具體過程。本文將以 <context:component-scan /> 節點爲例子,介紹自定義命名空間 context 的 component-scan 節點的解析過程。

 

正文

首先,我們回到 Spring IoC:parseCustomElement詳解 中的代碼塊5:NamespaceHandlerSupport.parse方法,代碼如下。

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    // 1.findParserForElement: 給element尋找對應的BeanDefinition解析器
    // 2.使用BeanDefinition解析器解析element節點
    return findParserForElement(element, parserContext).parse(element, parserContext);
}

當 element 爲 <context:component-scan /> 節點時,findParserForElement(element, parserContext) 會返回 ComponentScanBeanDefinitionParser,接着執行 ComponentScanBeanDefinitionParser.parse 方法。

 

ComponentScanBeanDefinitionParser.parse

@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    // 1.拿到<context:component-scan>節點的base-package屬性值
    String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
    // 2.解析佔位符, 例如 ${basePackage}
    basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
    // 3.解析base-package(允許通過 ",; \t\n" 中的任一符號填寫多個),例如: com.joonwhee.open.one;com.joonwhee.open.two
    String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);

    // Actually scan for bean definitions and register them.
    // 4.構建和配置ClassPathBeanDefinitionScanner
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    // 5.使用scanner在指定的basePackages包中執行掃描,返回已註冊的bean定義
    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    // 6.組件註冊(包括註冊一些內部的註解後置處理器、觸發註冊事件)
    registerComponents(parserContext.getReaderContext(), beanDefinitions, element);

    return null;
}

4.構建和配置 ClassPathBeanDefinitionScanner,見代碼塊1詳解

5.使用 scanner 在指定的 basePackages 包中執行掃描,返回已註冊的 BeanDefinitionHolder,見代碼塊5詳解

6.組件註冊,見代碼塊16詳解

 

代碼塊1:configureScanner

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
    // 1.解析use-default-filters屬性,默認爲true,用於指示是否使用默認的filter
    boolean useDefaultFilters = true;
    if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
        useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
    }

    // Delegate bean definition registration to scanner class.
    // 2.構建ClassPathBeanDefinitionScanner,將bean定義註冊委託給scanner類
    ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
    scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
    scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());

    // 3.解析resource-pattern屬性
    if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
        scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
    }

    try {
        // 4.解析name-generator屬性
        parseBeanNameGenerator(element, scanner);
    }
    catch (Exception ex) {
        parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
    }

    try {
        // 5.解析scope-resolver、scoped-proxy屬性
        parseScope(element, scanner);
    }
    catch (Exception ex) {
        parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
    }

    // 6.解析類型過濾器
    parseTypeFilters(element, scanner, parserContext);

    return scanner;
}

2.構建 ClassPathBeanDefinitionScanner,見代碼塊2詳解

6.解析類型過濾器,見代碼塊4詳解

 

代碼塊2:createScanner

protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
    return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
            readerContext.getEnvironment(), readerContext.getResourceLoader());
}

// ClassPathBeanDefinitionScanner.java
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
        Environment environment, ResourceLoader resourceLoader) {

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    if (useDefaultFilters) {
        // 1.註冊默認的filter
        registerDefaultFilters();
    }
    setEnvironment(environment);
    setResourceLoader(resourceLoader);
}

1.註冊默認的 filter,見代碼塊3詳解

 

代碼塊3:registerDefaultFilters

protected void registerDefaultFilters() {
    // 1.添加@Component註解Filter到includeFilters中
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
    try {
        // 2.添加@ManagedBean註解Filter到includeFilters中
        this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
        logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
        // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
    }
    try {
        // 3.添加@Named註解Filter到includeFilters中,這邊會拋ClassNotFoundException
        this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
        logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
        // JSR-330 API not available - simply skip.
    }
}

這邊會嘗試添加3個 AnnotationTypeFilter 到 includeFilters 中,但是默認情況下,添加 @Named 註解對應的 AnnotationTypeFilter 時會拋異常。因此,執行完該方法,includeFilters 會有兩個 AnnotationTypeFilter,分別對應 @Component 註解和 @ManagedBean 註解,如下圖所示。

 

代碼塊4:parseTypeFilters

protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
    // Parse exclude and include filter elements.
    ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
    NodeList nodeList = element.getChildNodes();
    // 1.遍歷解析element下的所有子節點
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            // 拿到節點的localName
            // 例如節點:<context:exclude-filter type="" expression=""/>,localName爲:exclude-filter
            String localName = parserContext.getDelegate().getLocalName(node);
            try {
                /**
                 * 例如
                 * <context:component-scan base-package="com.joonwhee.open">
                 *     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
                 * </context:component-scan>
                 */
                // 2.解析include-filter子節點
                if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
                    // 2.1 構建TypeFilter
                    TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                    // 2.2 添加到scanner的includeFilters屬性
                    scanner.addIncludeFilter(typeFilter);
                }
                // 3.解析exclude-filter子節點
                else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
                    // 3.1 構建TypeFilter
                    TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                    // 3.2 添加到scanner的excludeFilters屬性
                    scanner.addExcludeFilter(typeFilter);
                }
            } catch (Exception ex) {
                parserContext.getReaderContext().error(
                        ex.getMessage(), parserContext.extractSource(element), ex.getCause());
            }
        }
    }
}

protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) {
    // 1.獲取type、expression
    String filterType = element.getAttribute(FILTER_TYPE_ATTRIBUTE);
    String expression = element.getAttribute(FILTER_EXPRESSION_ATTRIBUTE);
    expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression);
    try {
        // 2.根據filterType,返回對應的TypeFilter,例如annotation返回AnnotationTypeFilter
        if ("annotation".equals(filterType)) {
            // 2.1 指定過濾的註解, expression爲註解的類全名稱, 例如: org.springframework.stereotype.Controller
            return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression));
        }
        else if ("assignable".equals(filterType)) {
            // 2.2 指定過濾的類或接口, 包括子類和子接口, expression爲類全名稱
            return new AssignableTypeFilter(classLoader.loadClass(expression));
        }
        else if ("aspectj".equals(filterType)) {
            // 2.3 指定aspectj表達式來過濾類, expression爲aspectj表達式字符串
            return new AspectJTypeFilter(expression, classLoader);
        }
        else if ("regex".equals(filterType)) {
            // 2.4 通過正則表達式來過濾類, expression爲正則表達式字符串
            return new RegexPatternTypeFilter(Pattern.compile(expression));
        }
        else if ("custom".equals(filterType)) {
            // 2.5 用戶自定義過濾器類型, expression爲自定義過濾器的類全名稱
            Class<?> filterClass = classLoader.loadClass(expression);
            // 自定義的過濾器必須實現TypeFilter接口, 否則拋異常
            if (!TypeFilter.class.isAssignableFrom(filterClass)) {
                throw new IllegalArgumentException(
                        "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
            }
            return (TypeFilter) BeanUtils.instantiateClass(filterClass);
        }
        else {
            throw new IllegalArgumentException("Unsupported filter type: " + filterType);
        }
    }
    catch (ClassNotFoundException ex) {
        throw new FatalBeanException("Type filter class not found: " + expression, ex);
    }
}

舉個例子:

我們知道,當我們配置了 component-scan 時,Spring會去掃描 base-package 下所有使用了 @Component(包括@Controller、@Repository、@Service) 註解的 bean。這是因爲 use-default-filters 屬性默認值爲 true,而通過代碼塊3我們知道,use-default-filters = true 時,includeFilters 會有兩個 AnnotationTypeFilter,分別對應 @Component 註解和 @ManagedBean 註解。

如果我們想排除掉使用了 @Controller 註解的 bean 時,就可以使用 exclude-filter 屬性,例如以下配置。

<context:component-scan base-package="com.joonwhee.open.demo">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

 

代碼塊5:doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
    // 1.遍歷basePackages
    for (String basePackage : basePackages) {
        // 2.掃描basePackage,將符合要求的bean定義全部找出來(這邊符合要求最常見的就是使用Component註解)
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // 3.遍歷所有候選的bean定義
        for (BeanDefinition candidate : candidates) {
            // 4.解析@Scope註解, 包括scopeName(默認爲singleton,常見的還有prototype), 和proxyMode(默認不使用代理, 可選接口代理/類代理)
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            // 5.使用beanName生成器來生成beanName
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                // 6.進一步處理BeanDefinition對象,比如: 此bean是否可以自動裝配到其他bean中
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                // 7.處理定義在目標類上的通用註解,包括@Lazy, @Primary, @DependsOn, @Role, @Description
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // 8.檢查beanName是否已經註冊過,如果註冊過,檢查是否兼容
            if (checkCandidate(beanName, candidate)) {
                // 9.將當前遍歷bean的 bean定義和beanName封裝成BeanDefinitionHolder
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                // 10.根據proxyMode的值(步驟4中解析), 選擇是否創建作用域代理
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 11.註冊BeanDefinition(註冊到beanDefinitionMap、beanDefinitionNames、aliasMap緩存)
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

2.掃描 basePackage,將符合要求的 bean 定義全部找出來,見代碼塊6詳解

4.解析 @Scope 註解,見代碼塊9詳解

6.進一步處理 BeanDefinition 對象,見代碼塊10詳解

7.處理定義在目標類上的通用註解,見代碼塊11詳解

8.檢查 beanName 是否已經註冊過,如果註冊過,檢查是否兼容,見代碼塊12詳解

10.根據 proxyMode 的值(步驟4中解析了該屬性),選擇是否創建作用域代理,見代碼塊13詳解

11.註冊 BeanDefinition,見代碼塊15詳解

 

代碼塊6:findCandidateComponents

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
    try {
        // 1.根據我們配置的包名,組裝成要掃描的通配包路徑,例如:com.joonwhee.open 會被組裝成: classpath*:com/joonwhee/open/**/*.class
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        // 2.根據通配包路徑匹配拿到所有匹配的類資源(本項目依賴的jar,如果路徑也符合,則會一起掃描進來)
        Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
        boolean traceEnabled = logger.isTraceEnabled();
        boolean debugEnabled = logger.isDebugEnabled();
        // 3.遍歷所有匹配的類資源
        for (Resource resource : resources) {
            if (traceEnabled) {
                logger.trace("Scanning " + resource);
            }
            if (resource.isReadable()) {
                try {
                    // 4.使用metadataReader讀取資源,MetadataReader是專門用來訪問元數據的類(包括: 類元數據ClassMetadata、註解元數據AnnotationMetadata等)
                    MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
                    // 5.使用過濾器檢查給定的類是否爲候選類(候選類: 與excludeFilters的所有Filter不匹配,並且與includeFilters的至少一個Filter匹配)
                    if (isCandidateComponent(metadataReader)) {
                        ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                        sbd.setResource(resource);
                        sbd.setSource(resource);
                        // 6.判斷sbd是否爲候選類(獨立的 && (具體的實現類 || (抽象類 && 類中有方法使用@Lookup註解)))
                        if (isCandidateComponent(sbd)) {
                            if (debugEnabled) {
                                logger.debug("Identified candidate component class: " + resource);
                            }
                            // 7.確定是候選類,則添加到candidates
                            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 (Throwable ex) {
                    throw new BeanDefinitionStoreException(
                            "Failed to read candidate component class: " + resource, ex);
                }
            }
            else {
                if (traceEnabled) {
                    logger.trace("Ignored because not readable: " + resource);
                }
            }
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
    }
    return candidates;
}

5.使用過濾器檢查給定的類是否爲候選類,見代碼塊7詳解

6.判斷 sbd 是否爲候選類,步驟5是使用過濾器進行檢查,而本方法則是單純的校驗候選者類,見代碼塊8詳解

 

代碼塊7:isCandidateComponent

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    for (TypeFilter tf : this.excludeFilters) {
        if (tf.match(metadataReader, this.metadataReaderFactory)) {
            // 如果metadataReader與excludeFilters中的任意一個匹配,則返回false,表示metadataReader對應的類不是候選者類
            return false;
        }
    }

    // includeFilters默認包含: org.springframework.stereotype.Component註解、javax.annotation.ManagedBean註解
    for (TypeFilter tf : this.includeFilters) {
        if (tf.match(metadataReader, this.metadataReaderFactory)) {
            // 如果metadataReader與includeFilters中的任意一個TypeFilter匹配(如果tf爲Component註解:metadataReader對應的類使用了Component則匹配),
            // 則判斷@Conditional註解是否匹配(@Conditional基本不用,此處不深入解析);如果匹配,則返回true,表示metadataReader對應的類爲候選者類
            return isConditionMatch(metadataReader);
        }
    }
    return false;
}

這邊的 excludeFilters 和 includeFilters 在上面的代碼塊3、代碼塊4中已經介紹過。默認情況下 excludeFilters 爲空,includeFilters 包含:@Component 註解的 TypeFilter、@ManagedBean 註解的 TypeFilter。

因此,在正常情況下,使用了 @Component(包括被 @Component 修飾的 @Controller、@Repository、@Service) 註解的類在這邊會返回 true,表示該類是候選者類。

 

代碼塊8:isCandidateComponent

protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    AnnotationMetadata metadata = beanDefinition.getMetadata();
    // isIndependent:確定底層類是否是獨立的,即它是否是頂級類或嵌套類(靜態內部類),它可以獨立於封閉類構造。
    // isConcrete:返回底層類是表示具體類,即:既不是接口也不是抽象類。
    // isAbstract:返回底層類是否標記爲抽象。
    // hasAnnotatedMethods:確定基礎類是否具有使用給定註解(@Lookup)類型進行註解(或元註解)的任何方法。
    return (metadata.isIndependent() && (metadata.isConcrete() ||
            (metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}

正常使用,在前兩個條件校驗完就會返回 true,不會走到後面兩個條件。

 

代碼塊9:resolveScopeMetadata

@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
    ScopeMetadata metadata = new ScopeMetadata();
    if (definition instanceof AnnotatedBeanDefinition) {
        AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
        AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
                annDef.getMetadata(), this.scopeAnnotationType);
        // 如果使用了@Scope註解
        if (attributes != null) {
            // 解析scopeName屬性
            metadata.setScopeName(attributes.getString("value"));
            // 解析proxyMode屬性
            ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
            if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
                proxyMode = this.defaultProxyMode;
            }
            metadata.setScopedProxyMode(proxyMode);
        }
    }
    return metadata;
}

如果使用了@Scope註解,則解析註解的屬性。這邊的 defaultProxyMode 取決於代碼塊1步驟5的 scope-resolver、scoped-proxy 屬性,默認爲 ScopedProxyMode.NO。可以通過 scoped-proxy 來設置,例如下面配置 defaultProxyMode 的值就爲 ScopedProxyMode.TARGET_CLASS。

<context:component-scan base-package="com.joonwhee.open.demo" scoped-proxy="targetClass">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

 

代碼塊10:postProcessBeanDefinition

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
    // 給beanDefinition設置默認值
    beanDefinition.applyDefaults(this.beanDefinitionDefaults);
    if (this.autowireCandidatePatterns != null) {
        // 設置此bean是否可以自動裝配到其他bean中, 默認爲true
        beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
    }
}

 

代碼塊11:processCommonDefinitionAnnotations

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    // 解析@Lazy註解, 設置是否延遲加載
    if (metadata.isAnnotated(Lazy.class.getName())) {
        abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value"));
    }
    else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) {
        abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value"));
    }

    // 解析@Primary註解, 自動裝配時當出現多個Bean都匹配時,被註解爲@Primary的Bean將作爲首選者,否則將拋出異常
    // (場景較小, 如果可能出現多個匹配者時, 可以使用@Autowired @Qualifier的組合)
    if (metadata.isAnnotated(Primary.class.getName())) {
        abd.setPrimary(true);
    }
    // 解析@DependOn註解
    if (metadata.isAnnotated(DependsOn.class.getName())) {
        abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value"));
    }

    if (abd instanceof AbstractBeanDefinition) {
        // 解析@Role註解
        AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
        if (metadata.isAnnotated(Role.class.getName())) {
            absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue());
        }
        // 解析@Description註解
        if (metadata.isAnnotated(Description.class.getName())) {
            absBd.setDescription(attributesFor(metadata, Description.class).getString("value"));
        }
    }
}

 

代碼塊12:checkCandidate

protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
    // 1.如果該註冊表(beanDefinitionMap緩存)沒有包含beanName, 則返回true,代表可以註冊該bean定義
    if (!this.registry.containsBeanDefinition(beanName)) {
        return true;
    }
    // 2.如果註冊表中包含beanName
    // 2.1拿到註冊表中該beanName的BeanDefinition
    BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
    // 2.2拿到原始BeanDefinition(使用了代理的BeanDefinition會有原始BeanDefinition)
    BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
    if (originatingDef != null) {
        // 2.3如果有原始BeanDefinition, 則使用原始BeanDefinition
        existingDef = originatingDef;
    }
    // 3.檢查新BeanDefinition是否與原BeanDefinition兼容,如果兼容則返回false,跳過註冊
    if (isCompatible(beanDefinition, existingDef)) {
        return false;
    }
    // 4.如果不兼容,則拋異常
    throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
            "' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
            "non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}

 

代碼塊13:applyScopedProxyMode

static BeanDefinitionHolder applyScopedProxyMode(
        ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

    ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
    // 1.如果不需要創建代理,則直接返回bean定義
    if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
        return definition;
    }
    // 2.判斷是使用基於類的代理還是基於接口的代碼, 基於類: 使用CGLIB代理, 基於接口: 使用JDK動態代理
    boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
    // 3.使用相應的代理模式, 創建一個scope代理
    return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

3.使用相應的代理模式,創建一個 scope 代理,見代碼塊14詳解

 

代碼塊14:createScopedProxy

public static BeanDefinitionHolder createScopedProxy(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {

    return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}

public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
                                                     BeanDefinitionRegistry registry, boolean proxyTargetClass) {

	// 拿到原始bean的beanName
	String originalBeanName = definition.getBeanName();
	// 拿到原始bean的BeanDefinition
	BeanDefinition targetDefinition = definition.getBeanDefinition();
	// 爲原始bean生成了一個新的beanName(加了個前綴: scopedTarget.)
	String targetBeanName = getTargetBeanName(originalBeanName);

	// Create a scoped proxy definition for the original bean name,
	// "hiding" the target bean in an internal target definition.
	// 使用ScopedProxyFactoryBean作爲beanClass創建代理BeanDefinition
	RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
	// 將原始bean封裝成BeanDefinitionHolder,設置到代理的decoratedDefinition屬性
	proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
	// 設置代理的原始BeanDefinition屬性值
	proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
	proxyDefinition.setSource(definition.getSource());
	proxyDefinition.setRole(targetDefinition.getRole());

	proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
	if (proxyTargetClass) {
		// 根據類做代理, proxyTargetClass屬性默認爲true,因此我們不需要在此處設置它
		targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
		// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
	} else {
		// 根據接口做代理, 設置proxyTargetClass屬性值爲false
		proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
	}

	// Copy autowire settings from original bean definition.
	// 從原始bean定義複製autowire設置
	proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
	proxyDefinition.setPrimary(targetDefinition.isPrimary());
	if (targetDefinition instanceof AbstractBeanDefinition) {
		proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
	}

	// The target bean should be ignored in favor of the scoped proxy.
	// 隱藏原始的bean
	targetDefinition.setAutowireCandidate(false);
	targetDefinition.setPrimary(false);

	// Register the target bean as separate bean in the factory.
	// 註冊原始bean的BeanDefinition
	registry.registerBeanDefinition(targetBeanName, targetDefinition);

	// Return the scoped proxy definition as primary bean definition
	// (potentially an inner bean).
	// 將代理bean封裝成BeanDefinitionHolder對象並返回
	return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}

 

代碼塊15:registerBeanDefinition

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    // 調用BeanDefinitionReaderUtils工具類來完成BeanDefinition的註冊
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

調用 BeanDefinitionReaderUtils 工具類來完成 BeanDefinition 的註冊,該方法在 Spring IoC:parseDefaultElement詳解 中的代碼塊13已經解析過。

 

代碼塊16:registerComponents

protected void registerComponents(
        XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) {

    Object source = readerContext.extractSource(element);
    // 1.使用註解的tagName(例如: context:component-scan)和source 構建CompositeComponentDefinition
    CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);

    // 2.將掃描到的所有BeanDefinition添加到compositeDef的nestedComponents屬性中
    for (BeanDefinitionHolder beanDefHolder : beanDefinitions) {
        compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder));
    }

    // Register annotation config processors, if necessary.
    boolean annotationConfig = true;
    if (element.hasAttribute(ANNOTATION_CONFIG_ATTRIBUTE)) {
        // 3.獲取component-scan標籤的annotation-config屬性值(默認爲true)
        annotationConfig = Boolean.valueOf(element.getAttribute(ANNOTATION_CONFIG_ATTRIBUTE));
    }
    if (annotationConfig) {
        // 4.如果annotation-config屬性值爲true,在給定的註冊表中註冊所有用於註解的Bean後置處理器
        Set<BeanDefinitionHolder> processorDefinitions =
                AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
        for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
            // 5.將註冊的註解後置處理器的BeanDefinition添加到compositeDef的nestedComponents屬性中
            compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition));
        }
    }

    // 6.觸發組件註冊事件,默認實現爲EmptyReaderEventListener(空實現,沒有具體操作)
    readerContext.fireComponentRegistered(compositeDef);
}

4.在給定的註冊表中註冊所有用於註解的 bean 後置處理器,見代碼塊17詳解

 

代碼塊17:registerAnnotationConfigProcessors

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
        BeanDefinitionRegistry registry, Object source) {

    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            // 1.設置dependencyComparator屬性
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }
        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            // 2.設置autowireCandidateResolver屬性(設置自動注入候選對象的解析器,用於判斷BeanDefinition是否爲候選對象)
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);

    // 3.註冊內部管理的用於處理@Configuration註解的後置處理器的bean
    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
        def.setSource(source);
        // 3.1 registerPostProcessor: 註冊BeanDefinition到註冊表中
        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 4.註冊內部管理的用於處理@Autowired、@Value、@Inject以及@Lookup註解的後置處理器的bean
    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 5.註冊內部管理的用於處理@Required註解的後置處理器的bean
    if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 6.註冊內部管理的用於處理JSR-250註解(例如@Resource, @PostConstruct, @PreDestroy)的後置處理器的bean
    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 7.註冊內部管理的用於處理JPA註解的後置處理器的bean
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition();
        try {
            def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
                    AnnotationConfigUtils.class.getClassLoader()));
        } catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
                    "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
        }
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // 8.註冊內部管理的用於處理@EventListener註解的後置處理器的bean
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }
    // 9.註冊內部管理用於生產ApplicationListener對象的EventListenerFactory對象
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
        RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
        def.setSource(source);
        beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

3.1 註冊後置處理器的 BeanDefinition 到註冊表中,見代碼塊18詳解

 

代碼塊18:registerPostProcessor

private static BeanDefinitionHolder registerPostProcessor(
        BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

    // 1.設置role
    definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    // 2.註冊BeanDefinition
    registry.registerBeanDefinition(beanName, definition);
    // 3.封裝成BeanDefinitionHolder並返回
    return new BeanDefinitionHolder(definition, beanName);
}

2.註冊 BeanDefinition,該方法會走到 DefaultListableBeanFactory.registerBeanDefinition 方法,該方法在 Spring IoC:parseDefaultElement詳解 中的代碼塊14已經解析過。

 

至此,<context:component-scan> 節點解析已經完成,主要做的事情有:

  1. 掃描 base-package 目錄,將使用了 @Component、@Controller、@Repository、@Service 註解的 bean 註冊到註冊表中(其實就是beanDefinitionMap、beanDefinitionNames、aliasMap緩存中),跟之前解析默認命名空間一樣,也是在後續創建 bean 時需要使用這些緩存。
  2. 添加了幾個內部的註解相關的後置處理器:ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor 等。

 

總結

同時,本文的結束,也標誌着 obtainFreshBeanFactory 方法的詳解正式結束。

簡單來說,有以下幾個主要操作:

  1. 根據 web.xml 中 contextConfigLocation 配置的路徑,讀取 Spring 配置文件,並封裝成 Resource。
  2. 根據 Resource 加載 XML 配置文件,並解析成 Document 對象 。
  3. 拿到 Document 中的根節點,遍歷根節點和所有子節點。
  4. 根據命名空間,進行不同的解析,將 bean 節點內容解析成 BeanDefinition。
  5. 將 BeanDefinition 註冊到註冊表中(也就是beanDefinitionMap、beanDefinitionNames、aliasMap緩存)。

執行完 obtainFreshBeanFactory 方法,我們得到了三個重要的對象:

  • 新的 BeanFactory。
  • beanDefinitionNames 緩存。
  • beanDefinitionMap 緩存。

這三個對象在之後的 IoC 構建過程中會發揮重要的作用。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章