国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring源碼閱讀——ClassPathXmlApplicationContext(三)

gecko23 / 1396人閱讀

摘要:在上一篇源碼閱讀二文章的最后,需要解析元素,創建實例完成必須的裝配和進行最終的注冊來完成元素的解析和注冊,下面分別閱讀三步的源碼。

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

創建BeanDefinitionHolder實例

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

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 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 實例,下面是此方法的實現:

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)方法的實現如下:

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 beanDefinitionMap = new ConcurrentHashMap<>(64);
registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())

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的解析。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76389.html

相關文章

  • Spring源碼閱讀——ClassPathXmlApplicationContext

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

    xbynet 評論0 收藏0
  • Spring源碼閱讀——ClassPathXmlApplicationContext

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

    AndroidTraveler 評論0 收藏0
  • Spring源碼閱讀——ClassPathXmlApplicationContext(一)

    摘要:的繼承關系繼承了,實現了接口。是所有容器的頂級接口,中所有容器都是基于的。方法創建一個新的容器。在本方法中,最重要的是,調用這個方法解析配置文件,注冊。 ClassPathXmlApplicationContext的繼承關系 ClassPathXmlApplicationContext繼承了AbstractXmlApplicationContext,實現了ApplicationCont...

    taowen 評論0 收藏0
  • Spring源碼閱讀——ClassPathXmlApplicationContext(四)

    摘要:在的方法中,遍歷每一個節點,判斷是否為默認命名空間中的節點,如果是非默認命名空間的,調用方法進行處理。在學習自定義標簽解析之前,先寫一個自定義標簽的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍歷每一...

    silenceboy 評論0 收藏0
  • Spring源碼閱讀——ClassPathXmlApplicationContext(四)

    摘要:在的方法中,遍歷每一個節點,判斷是否為默認命名空間中的節點,如果是非默認命名空間的,調用方法進行處理。在學習自定義標簽解析之前,先寫一個自定義標簽的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍歷每一...

    wmui 評論0 收藏0

發表評論

0條評論

gecko23

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<