Spring源碼閱讀——ClassPathXmlApplicationContext(三)

在上一篇Spring源碼閱讀——ClassPathXmlApplicationContext(二)文章的最後,須要解析bean元素,建立BeanDefinitionHolder實例、完成必須的裝配和進行最終的註冊bean來完成bean元素的解析和註冊,下面分別閱讀三步的源碼。node

建立BeanDefinitionHolder實例

BeanDefinitionHolder的建立是委託給BeanDefinitionParserDelegate這個代理類的parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)方法來完成的,此方法的實現以下:spring

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        // 獲取id屬性值
        String id = ele.getAttribute(ID_ATTRIBUTE);
        // 獲取name屬性值
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
        //解析name屬性值,將全部name放入List中
        List<String> aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        // 賦值beanName爲id
        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            // 若是id爲空,且name屬性不爲空,取第一個name爲beanName
            beanName = aliases.remove(0);
            if (logger.isDebugEnabled()) {
                logger.debug("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            // 檢查惟一性
            checkNameUniqueness(beanName, aliases, ele);
        }
        // 解析bean元素
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            // 若是beanName爲空
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        // 生成默認的beanName
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        // 生成默認的beanName
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // 經過beanClass生成一個alias
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            // 獲得別名數組
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            // 建立BeanDefinitionHolder對象並返回
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

在上述源碼中,調用了parseBeanDefinitionElement(ele, beanName, containingBean)方法建立AbstractBeanDefinition 實例,下面是此方法的實現:segmentfault

public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        // 根據beanName建立BeanEntry實體,而且push BeanEntry
        this.parseState.push(new BeanEntry(beanName));
        // 獲取class屬性值
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        // 獲取parent屬性值
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
            // 建立AbstractBeanDefinition實例
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 設置AbstractBeanDefinition實例的其餘各類屬性
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            // 獲取子元素description
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            // 獲取子元素meta
            parseMetaElements(ele, bd);
            // 解析子元素lookup-method
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            // 解析子元素replaced-method
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            // 解析子元素constructor-arg
            parseConstructorArgElements(ele, bd);
            // 解析子元素property
            parsePropertyElements(ele, bd);
            // 解析子元素qualifier
            parseQualifierElements(ele, bd);

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

            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 {
            // pop BeanEntry
            this.parseState.pop();
        }

        return null;
    }

若是有非默認命名空間,繼續裝飾此實例

decorateBeanDefinitionIfRequired(ele, bdHolder)接口的最終實現以下:數組

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
            Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {

        BeanDefinitionHolder finalDefinition = definitionHolder;

        // 根據自定義屬性裝飾
       // 獲取全部屬性
        NamedNodeMap attributes = ele.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {
            Node node = attributes.item(i);
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }

        // 裝飾基於自定義嵌套元素的裝飾
        // 獲取全部嵌套元素
        NodeList children = ele.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
            }
        }
        return finalDefinition;
    }

此方法在存在非默認命名空間時,解析自定義的屬性和嵌套元素,decorateIfRequired(node, finalDefinition, containingBd)方法的實現以下:ide

public BeanDefinitionHolder decorateIfRequired(
            Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

        // 獲取命名空間uri
        String namespaceUri = getNamespaceURI(node);
        // 若是不是默認命名空間uri
        if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
            // 獲取命名空間handler
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler != null) {
                // 調用此handler 的decorate方法建立BeanDefinitionHolder實例
                BeanDefinitionHolder decorated =
                        handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
                if (decorated != null) {
                    return decorated;
                }
            }
            else if (namespaceUri.startsWith("http://www.springframework.org/")) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
            }
            else {
                // A custom namespace, not to be handled by Spring - maybe "xml:...".
                if (logger.isDebugEnabled()) {
                    logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
                }
            }
        }
        return originalDef;
    }

註冊最終的實例

接下來是往註冊表中註冊bean,BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())的實現以下:學習

public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        String beanName = definitionHolder.getBeanName();
        // beanName 做爲key,註冊bean definition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // beanName 做爲key,註冊alias
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

在SimpleBeanDefinitionRegistry類中,定義了註冊bean definition的Mam對象,map初始大小爲64,以下:
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())ui

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

        Assert.hasText(beanName, "'beanName' must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

經過這篇文章,學習了ClassPathXmlApplicationContext的啓動解析默認命名空間中元素的解析過程,下面繼續學習自定義命名空間中bean的解析。this

相關文章
相關標籤/搜索