4.spring初級容器XmlBeanFactory初始化(三)

開篇

  1. 通過前一篇文章3.spring初級容器XmlBeanFactory初始化(二),我們已經(jīng)知道了spring是如何解析xml標(biāo)簽,如:meta,lookup-method等,解析完成之后,將會(huì)把解析好的標(biāo)簽信息封裝到BeanDefinition中.
  2. 現(xiàn)在我們來看下,BeanDefinition是如何注冊到spring容器中的

BeanDefinition是從哪里開始注冊到spring容器中的

在前兩篇的文章中,我們重點(diǎn)看了spring如何解析bean標(biāo)簽和屬性的,在解析完bean標(biāo)簽和屬性之后,將解析的結(jié)果放到BeanDefinition中,最后返回一個(gè)GenericBeanDefinition類型的BeanDefinition


    /**
     * Parse the bean definition itself, without regard to name or aliases. May return
     * {@code null} if problems occurred during the parsing of the bean definition.
     */
    @Nullable
    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));

        String className = null;
        //1.如果標(biāo)簽中存在class屬性,那么就獲取class屬性值
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        String parent = null;
        //2.如果標(biāo)簽中存在parent標(biāo)簽,那么就獲取parent標(biāo)簽的屬性值
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
            //3.通過屬性class和parent,初步創(chuàng)建AbstractBeanDefinition
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);

            //4.解析bean標(biāo)簽中的各種屬性,并封裝到AbstractBeanDefinition中
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

            // 5.解析標(biāo)簽中各種子標(biāo)簽元素,并將解析結(jié)果封裝到AbstractBeanDefinition中

            // 解析bean標(biāo)簽中的meta
            parseMetaElements(ele, bd);
            // 解析bean標(biāo)簽中的lookup-method子標(biāo)簽元素
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            // 解析bean標(biāo)簽中replace-method子標(biāo)簽元素
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            // 解析bean的子標(biāo)簽constructor-arg
            parseConstructorArgElements(ele, bd);
            //解析bean的子標(biāo)簽property
            parsePropertyElements(ele, bd);
            //解析bean的子標(biāo)簽qualifier
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            //6.返回bd
            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

返回之后,我們繼續(xù)看調(diào)用parseBeanDefinitionElement方法的地方

/**
     * Parses the supplied {@code <bean>} element. May return {@code null}
     * if there were errors during parse. Errors are reported to the
     * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
     */
    @Nullable
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        //1.解析bean標(biāo)簽中的id和name屬性
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        //2.將屬性name通過","或";"分隔符進(jìn)行分割,并將數(shù)據(jù)添加到aliases中
        List<String> aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        // 3.如果屬性id為空,那么就取aliases集合中的第一個(gè)value的值,作為bean的名稱
        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isTraceEnabled()) {
                logger.trace("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        // 4. 開始解析bean標(biāo)簽,并將解析結(jié)果封裝為AbstractBeanDefinition
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            // beanName不為空,直接跳過
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // Register an alias for the plain bean class name, if still possible,
                        // if the generator returned the class name plus a suffix.
                        // This is expected for Spring 1.2/2.0 backwards compatibility.
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isTraceEnabled()) {
                        logger.trace("Neither XML 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            // 5. 將解析的beanDefinition,beanName和aliase,創(chuàng)建一個(gè)BeanDefinitionHolder
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

這里會(huì)將解析好的bean標(biāo)簽的BeanDefinition連同aliasesArray一起封裝成BeanDefinitionHolder,BeanDefinitionHolder也可以理解成BeanDefinition的一個(gè)對象。

  1. 當(dāng)我們繼續(xù)向上去找調(diào)用源頭的時(shí)候,就會(huì)發(fā)現(xiàn)了,這里在解析完bean的屬性和標(biāo)簽之后,將解析的屬性和標(biāo)簽以BeanDefinitionHolder類型返回,其實(shí)就是一個(gè)BeanDefinition對象
  2. 然后執(zhí)行delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);,這里可以忽略,因?yàn)辄c(diǎn)進(jìn)去看下,基本上就是一些自定義標(biāo)簽的校驗(yàn)
  3. 接著執(zhí)行的就是我們的核心,把bean注如到spring容器當(dāng)中BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
/**
     * Process the given bean element, parsing the bean definition
     * and registering it with the registry.
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 1.解析bean標(biāo)簽元素
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                // 將解析到的bean注冊到spring容器當(dāng)中
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

接下來,我們來看下,bean是如何注入到spring容器中的

/**
     * Register the given bean definition with the given bean factory.
     * @param definitionHolder the bean definition including name and aliases
     * @param registry the bean factory to register with
     * @throws BeanDefinitionStoreException if registration failed
     */
    public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        //首先,拿到bean的名稱
        String beanName = definitionHolder.getBeanName();
        //注冊BeanDefinition到spring容器中
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // Register aliases for bean name, if any.
        //如果bean有別名,那么就注冊bean的別名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

繼續(xù)看下registerBeanDefinition

@Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        //如果beanDefinition是AbstractBeanDefinition的實(shí)例
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                //校驗(yàn)beanDefinition中的methodOverrides屬性
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        //判斷beanDefinitionMap中是否已經(jīng)存在beanName對應(yīng)的BeanDefinition,這里的beanDefinitionMap
        //就是spring容器
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            //如果配置BeanDefinition不能被覆蓋,那么就直接報(bào)錯(cuò)
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                //直接將beanDefinition放入到beanDefinitionMap
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //記錄beanName
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        //如果當(dāng)前需要注冊的bean的beanName,已經(jīng)在spring容器中存在beanDefinition
        //或者已經(jīng)根據(jù)beanName創(chuàng)建出來對應(yīng)的bean的單例bean對象了
        if (existingDefinition != null || containsSingleton(beanName)) {
            //重新調(diào)整beanName對應(yīng)的緩存
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }

1.首先要校驗(yàn)beanDefinition中的methodOverrides屬性,在方法validate中不允許methodOverrides屬性和factoryMethodName屬性同時(shí)設(shè)置

1.1 在解析lookup-method標(biāo)簽和replaced-method標(biāo)簽時(shí),會(huì)將這兩個(gè)標(biāo)簽需要覆蓋的方法名設(shè)置到MethodOverrides中
1.2 一旦MethodOverrides不為空,這就意味著Spring創(chuàng)建出來bean還要重新覆寫這些方法
1.3 而factoryMethodName屬性也就是工廠方法的名稱,通過工廠方法也可以創(chuàng)建一個(gè)bean出來,但是這相比于Spring默認(rèn)的創(chuàng)建方式而言,算是一種不允許外界覆蓋bean中方法的創(chuàng)建方式了
1.4 也就是說要么我們通過工廠方法創(chuàng)建bean,要么就按Spring普通的方式來創(chuàng)建bean,兩者選其一

  1. 接下來,可以看到,spring容器就是一個(gè)Map,key為beanName,value為BeanDefinition,beanDefinitionMap是成員變量,難免會(huì)有并發(fā)安全問題,所以這里使用多線程安全的ConcurrentHashMap作為Spring的容器

看完beanDefinition是如何注冊到spring的容器之后,會(huì)繼續(xù)判斷是否有別名,如果有別名的話,就注冊別名


檢查bean是否有別名
@Override
    public void registerAlias(String name, String alias) {
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        synchronized (this.aliasMap) {
            //如果別名alias和bean的名稱相同
            if (alias.equals(name)) {
                //就不記錄該別名,并且從別名map中刪除
                this.aliasMap.remove(alias);
                if (logger.isDebugEnabled()) {
                    logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
                }
            }
            else {
                String registeredName = this.aliasMap.get(alias);
                if (registeredName != null) {
                    //如果最新的別名,和從別名map中獲取的相同,那么就直接空操作,避免重復(fù)操作
                    if (registeredName.equals(name)) {
                        // An existing alias - no need to re-register
                        return;
                    }
                    //如果不允許表名覆蓋,就報(bào)錯(cuò)
                    if (!allowAliasOverriding()) {
                        throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                                name + "': It is already registered for name '" + registeredName + "'.");
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                                registeredName + "' with new target name '" + name + "'");
                    }
                }
                //檢查別名是否存在循環(huán)
                checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
                if (logger.isTraceEnabled()) {
                    logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
                }
            }
        }
    }

總結(jié)

spring初級容器初始化
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容