<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring 是如何解析 標簽的?

          共 2269字,需瀏覽 5分鐘

           ·

          2021-02-18 09:59

          前情回顧

          上回「Spring IoC 容器初始化(2)」說到了 Spring 如何解析我們定義的 標簽,代碼跟進了一層又一層,跋山涉水,最終來到了 BeanDefinitionParserDelegate#parseBeanDefinitionElement 方法。不過這個方法只是表面,并未深入解析 中的 class 等屬性以及 property 等子標簽。

          本文繼續(xù)跟進。

          嗯,還是要耐著點性子,最好寫個 demo 打斷點跟蹤一下,這樣理解起來才更深刻。

          如何解析 的內(nèi)容?

          繼續(xù)看代碼:

          public?class?BeanDefinitionParserDelegate?{
          ????public?AbstractBeanDefinition?parseBeanDefinitionElement(
          ??? Element?ele,?String?beanName,?@Nullable?BeanDefinition?containingBean)
          ?
          {

          ?? String?className?=?null;
          ?? //?讀取??標簽的?class?屬性
          ?? if?(ele.hasAttribute(CLASS_ATTRIBUTE))?{
          ??? className?=?ele.getAttribute(CLASS_ATTRIBUTE).trim();
          ?? }
          ?? String?parent?=?null;
          ?? //?讀取??標簽的?parent?屬性
          ?? if?(ele.hasAttribute(PARENT_ATTRIBUTE))?{
          ??? parent?=?ele.getAttribute(PARENT_ATTRIBUTE);
          ?? }

          ?? try?{
          ??? //?創(chuàng)建?BeanDefinition?對象(GenericBeanDefinition)
          ??? AbstractBeanDefinition?bd?=?createBeanDefinition(className,?parent);

          ??? //?解析?scope、lazy-init、autowire?等屬性
          ??? parseBeanDefinitionAttributes(ele,?beanName,?containingBean,?bd);
          ??? bd.setDescription(DomUtils.getChildElementValueByTagName(ele,?DESCRIPTION_ELEMENT));

          ??? //?解析?meta?標簽
          ??? parseMetaElements(ele,?bd);
          ????????????
          ??? //?解析?lookup-method?標簽
          ??? parseLookupOverrideSubElements(ele,?bd.getMethodOverrides());

          ??? //?解析?replace-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?...
          ? }
          }

          這里才是真正解析 標簽內(nèi)容的地方,比如常見的 class、parent、scope、lazy-init、autowire、property、constructor-arg 等,還有不常見的 lookup-method、replace-method 等。

          該方法內(nèi)部調(diào)用了一個個方法去解析不同的標簽。這里我們只跟進常見的 property 如何解析,其他方法大體也都差不多,有興趣可以自行研究。

          parsePropertyElements 方法代碼如下:

          public?class?BeanDefinitionParserDelegate?{
          ? //?解析?property?標簽
          ? public?void?parsePropertyElements(Element?beanEle,?BeanDefinition?bd)?{
          ?? NodeList?nl?=?beanEle.getChildNodes();
          ?? for?(int?i?=?0;?i???? Node?node?=?nl.item(i);
          ??? //?篩選??標簽
          ??? if?(isCandidateElement(node)?&&?nodeNameEquals(node,?PROPERTY_ELEMENT))?{
          ???? parsePropertyElement((Element)?node,?bd);
          ??? }
          ?? }
          ? }

          ? public?void?parsePropertyElement(Element?ele,?BeanDefinition?bd)?{
          ?? //?property?標簽的?name?屬性
          ?? String?propertyName?=?ele.getAttribute(NAME_ATTRIBUTE);
          ?? if?(!StringUtils.hasLength(propertyName))?{
          ??? //?error
          ??? return;
          ?? }
          ?? this.parseState.push(new?PropertyEntry(propertyName));
          ?? try?{
          ??? if?(bd.getPropertyValues().contains(propertyName))?{
          ???? //?error
          ???? return;
          ??? }
          ??? //?這里解析得到的是?RuntimeBeanReference?或者?TypedStringValue
          ??? Object?val?=?parsePropertyValue(ele,?bd,?propertyName);
          ??? PropertyValue?pv?=?new?PropertyValue(propertyName,?val);
          ??? parseMetaElements(ele,?pv);
          ??? pv.setSource(extractSource(ele));
          ??? //?將解析到的值添加到?BeanDefinition?的屬性列表
          ??? bd.getPropertyValues().addPropertyValue(pv);
          ?? }
          ?? finally?{
          ??? this.parseState.pop();
          ?? }
          ? }????
          }

          這個方法主要做了什么呢?

          1. 遍歷節(jié)點并找到 property 標簽
          2. 解析 property 標簽的 name 屬性,將它對應的值封裝為 RuntimeBeanReference 類型或者 TypedStringValue 類型(其中前者對應 ref 屬性,后者對應 value 屬性,可參考前文 application-ioc.xml 文件),然后再封裝為 PropertyValue 類型,并保存到 BeanDefinition 的屬性列表中。

          解析 ref 和 value 的過程如下:

          public?class?BeanDefinitionParserDelegate?{

          public?Object?parsePropertyValue(Element?ele,?BeanDefinition?bd,?@Nullable?String?propertyName)?{
          ?? String?elementName?=?(propertyName?!=?null??
          ???? "?element?for?property?'"?+?propertyName?+?"'"?:
          ???? "?element");

          ?? //?Should?only?have?one?child?element:?ref,?value,?list,?etc.
          NodeList?nl?=?ele.getChildNodes();
          ?? Element?subElement?=?null;
          ?? for?(int?i?=?0;?i? ??Node?node?=?nl.item(i);
          ??? if?(node?instanceof?Element?&&?!nodeNameEquals(node,?DESCRIPTION_ELEMENT)?&&
          ????? !nodeNameEquals(node,?META_ELEMENT))?{
          ???? //?Child?element?is?what?we're?looking?for.
          ???? if?(subElement?!=?null)?{
          ????? error(elementName?+?"?must?not?contain?more?than?one?sub-element",?ele);
          ???? }
          ???? else?{
          ????? subElement?=?(Element)?node;
          ???? }
          ??? }
          ?? }

          ????//?ref?和?value?屬性,二者不能并存
          ?? boolean?hasRefAttribute?=?ele.hasAttribute(REF_ATTRIBUTE);
          ?? boolean?hasValueAttribute?=?ele.hasAttribute(VALUE_ATTRIBUTE);
          ?? if?((hasRefAttribute?&&?hasValueAttribute)?||
          ???? ((hasRefAttribute?||?hasValueAttribute)?&&?subElement?!=?null))?{
          ??? error(elementName?+
          ????? "?is?only?allowed?to?contain?either?'ref'?attribute?OR?'value'?attribute?OR?sub-element",?ele);
          ?? }

          ????//?ref?屬性
          ?? if?(hasRefAttribute)?{
          ??? String?refName?=?ele.getAttribute(REF_ATTRIBUTE);
          ??? if?(!StringUtils.hasText(refName))?{
          ???? error(elementName?+?"?contains?empty?'ref'?attribute",?ele);
          ??? }
          ??????//?封裝為?RuntimeBeanReference?類型
          ??? RuntimeBeanReference?ref?=?new?RuntimeBeanReference(refName);
          ??? ref.setSource(extractSource(ele));
          ??? return?ref;
          ?? }
          ????//?value?屬性
          ?? else?if?(hasValueAttribute)?{
          ???? //?封裝為?TypedStringValue?類型
          ??? TypedStringValue?valueHolder?=?new?TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
          ??? valueHolder.setSource(extractSource(ele));
          ??? return?valueHolder;
          ?? }
          ????//?若還有子元素,繼續(xù)解析
          ?? else?if?(subElement?!=?null)?{
          ??????//?這里包含了?property?標簽的子標簽,例如?list、map、set?等
          ??? return?parsePropertySubElement(subElement,?bd);
          ?? }
          ?? else?{
          ??? error(elementName?+?"?must?specify?a?ref?or?value",?ele);
          ??? return?null;
          ?? }
          ? }
          }

          property 標簽的解析算是相對復雜的,其他標簽(meta、constructor-arg 等)的解析過程大體是類似的,不再一一分析。

          經(jīng)過 BeanDefinitionParserDelegate#parseBeanDefinitionElement 方法的解析和封裝后,就得到了保存我們自定義 bean 信息的 BeanDefinition,即 GenericBeanDefinition。Spring 又把 BeanDefinition 和別名信息封裝成了 BeanDefinitionHolder:

          public?class?BeanDefinitionParserDelegate?{
          ??public?BeanDefinitionHolder?parseBeanDefinitionElement(Element?ele,?@Nullable?BeanDefinition?containingBean)?{
          ?? String?id?=?ele.getAttribute(ID_ATTRIBUTE);
          ?? String?nameAttr?=?ele.getAttribute(NAME_ATTRIBUTE);

          ?? //?...

          ????//?解析后得到的?BeanDefinition
          ?? AbstractBeanDefinition?beanDefinition?=?parseBeanDefinitionElement(ele,?beanName,?containingBean);
          ?? if?(beanDefinition?!=?null)?{
          ??? //?...
          ??? String[]?aliasesArray?=?StringUtils.toStringArray(aliases);
          ??? return?new?BeanDefinitionHolder(beanDefinition,?beanName,?aliasesArray);
          ?? }

          ?? return?null;
          ? }
          }

          此外,在向 IoC 容器注冊之前,還有一個 decorateBeanDefinitionIfRequired 方法,它主要是用來處理默認名稱空間(即 http://www.springframework.org/schema/beans)之外的 bean 定義,比如 、 等,這里仍然先沿著主線走,暫不深入分析。

          接下來就是將 BeanDefinition 注冊到 IoC 容器:

          public?class?DefaultBeanDefinitionDocumentReader?implements?BeanDefinitionDocumentReader?{
          //?...
          ????
          ? protected?void?processBeanDefinition(Element?ele,?BeanDefinitionParserDelegate?delegate)?{
          ?? //?解析后的?BeanDefinition?封裝成的?BeanDefinitionHolder
          ?? BeanDefinitionHolder?bdHolder?=?delegate.parseBeanDefinitionElement(ele);
          ?? if?(bdHolder?!=?null)?{
          ??? bdHolder?=?delegate.decorateBeanDefinitionIfRequired(ele,?bdHolder);
          ??? try?{
          ???? //?Register?the?final?decorated?instance.
          ????????//?注冊?BeanDefinition
          ???? 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));
          ?? }
          ?}
          }
          public?abstract?class?BeanDefinitionReaderUtils?{
          ??//?...

          ??public?static?void?registerBeanDefinition(
          ?? BeanDefinitionHolder?definitionHolder,?BeanDefinitionRegistry?registry)

          ??? throws?BeanDefinitionStoreException?
          {

          ?? //?Register?bean?definition?under?primary?name.
          ?? String?beanName?=?definitionHolder.getBeanName();
          ?? registry.registerBeanDefinition(beanName,?definitionHolder.getBeanDefinition());

          ?? //?Register?aliases?for?bean?name,?if?any.
          ?? String[]?aliases?=?definitionHolder.getAliases();
          ?? if?(aliases?!=?null)?{
          ??? for?(String?alias?:?aliases)?{
          ???? registry.registerAlias(beanName,?alias);
          ??? }
          ?? }
          ? }
          }

          IoC 容器是哪個?如何注冊呢?

          前文提到過,Spring 默認的 IoC 容器是 DefaultListableBeanFactory,來看下它的繼承結(jié)構(gòu):

          可以看到 DefaultListableBeanFactory 實現(xiàn)了 BeanDefinitionRegistry 接口。

          所謂的“注冊”到 IoC 容器,其實就是把 BeanDefinition 保存到了 DefaultListableBeanFactory ?持有的一個 Map 中,如下:

          public?class?DefaultListableBeanFactory?extends?AbstractAutowireCapableBeanFactory
          ??implements?ConfigurableListableBeanFactory,?BeanDefinitionRegistry,?Serializable?
          {
          ??//?...

          ??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");

          ?? if?(beanDefinition?instanceof?AbstractBeanDefinition)?{
          ??? try?{
          ???? ((AbstractBeanDefinition)?beanDefinition).validate();
          ??? }
          ??? catch?(BeanDefinitionValidationException?ex)?{
          ???? throw?new?BeanDefinitionStoreException(beanDefinition.getResourceDescription(),?beanName,
          ?????? "Validation?of?bean?definition?failed",?ex);
          ??? }
          ?? }

          ?? //?獲取已存在的?BeanDefinition
          ?? BeanDefinition?existingDefinition?=?this.beanDefinitionMap.get(beanName);
          ?? if?(existingDefinition?!=?null)?{
          ??? if?(!isAllowBeanDefinitionOverriding())?{
          ???? throw?new?BeanDefinitionOverrideException(beanName,?beanDefinition,?existingDefinition);
          ??? }
          ??????//?這幾個異常信息是不是有點眼熟?
          ??? else?if?(existingDefinition.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?updatedDefinitions?=?new?ArrayList<>(this.beanDefinitionNames.size()?+?1);
          ????? updatedDefinitions.addAll(this.beanDefinitionNames);
          ????? updatedDefinitions.add(beanName);
          ????? this.beanDefinitionNames?=?updatedDefinitions;
          ????? removeManualSingletonName(beanName);
          ???? }
          ??? }
          ??? else?{
          ?????? //?注冊到?Map?中
          ???? //?Still?in?startup?registration?phase
          ???? this.beanDefinitionMap.put(beanName,?beanDefinition);
          ???? this.beanDefinitionNames.add(beanName);
          ???? removeManualSingletonName(beanName);
          ??? }
          ??? this.frozenBeanDefinitionNames?=?null;
          ?? }

          if?(existingDefinition?!=?null?||?containsSingleton(beanName))?{
          ??? resetBeanDefinition(beanName);
          ?? }
          ?? else?if?(isConfigurationFrozen())?{
          ??? clearByTypeCache();
          ?? }
          ? }
          }

          上面幾個異常信息是不是有點眼熟?

          這個 beanDefinitionMap 是個什么呢?它就是個 Map:

          /**?Map?of?bean?definition?objects,?keyed?by?bean?name.?*/
          private?final?Map?beanDefinitionMap?=?new?ConcurrentHashMap<>(256);

          小結(jié)

          到這里,Spring 已經(jīng)從我們定義的 application-ioc.xml 文件中讀取和解析到了 標簽的信息,并將其轉(zhuǎn)換為內(nèi)部的數(shù)據(jù)結(jié)構(gòu) BeanDefinition,然后注冊到了 IoC 容器(也就是 DefaultListableBeanFactory)。

          為了有個整體的把握,這里把主要流程梳理成了一個思維導圖:

          其實前面幾篇文章主要是第一個步驟,也就是「初始化 BeanFactory,注冊 Bean 定義」,而且只是沿著一條主線走下來的,其它細節(jié)部分有興趣的小伙伴可以自行研究。

          IoC 容器已經(jīng)建立,而且 BeanDefinition 也放進去了,如何從容器拿到我們想要的對象呢?

          欲知后事如何,且聽下回分解~


          咱也來體驗一下這個名片

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91九色91蝌蚪91成人 | 四虎网站黄色 | 艹逼视频在线免费观看 | 一区二区在线视频播放 | 九九国产精品 |