歡迎光臨
每天分享高質量文章

【死磕 Spring】—– IOC 之解析 bean 標簽:BeanDefinition

點選上方“Java技術驛站”,選擇“置頂公眾號”。

有內涵、有價值的文章第一時間送達!

精品專欄

 

前面歷經千辛萬苦終於到達解析 bean 標簽步驟來了,解析 bean 標簽的過程其實就是構造一個 BeanDefinition 物件的過程,  元素標簽擁有的配置屬性,BeanDefinition 均提供了相應的屬性,與之一一對應。所以我們有必要對 BeanDefinition 有一個整體的認識。

BeanDefinition

BeanDefinition 是一個介面,它描述了一個 Bean 實體,包括屬性值、構造方法值和繼承自它的類的更多資訊。它繼承 AttributeAccessor 和 BeanMetadataElement 介面。兩個介面定義如下:

  • AttributeAccessor :定義了與其它物件的(元資料)進行連線和訪問的約定,即對屬性的修改,包括獲取、設定、刪除。

  • BeanMetadataElement:Bean 元物件持有的配置元素可以透過 getSource() 方法來獲取。

BeanDefinition 整個結構如下圖:

我們常用的三個實現類有:ChildBeanDefinition、GenericBeanDefinition、RootBeanDefinition,三者都繼承 AbstractBeanDefinition。如果配置檔案中定義了父  和 子  ,則父  用 RootBeanDefinition表示,子  用 ChildBeanDefinition 表示,而沒有父  的就使用RootBeanDefinition 表示。GenericBeanDefinition 為一站式服務類。AbstractBeanDefinition對三個子類共同的類資訊進行抽象。

解析 Bean 標簽

在 BeanDefinitionParserDelegate.parseBeanDefinitionElement() 中完成 Bean 的解析,傳回的是一個已經完成對  標簽解析的 BeanDefinition 實體。在該方法內部,首先呼叫 createBeanDefinition() 方法建立一個用於承載屬性的 GenericBeanDefinition 實體,如下:

  1.    protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)

  2.            throws ClassNotFoundException {

  3.        return BeanDefinitionReaderUtils.createBeanDefinition(

  4.                parentName, className, this.readerContext.getBeanClassLoader());

  5.    }

委託 BeanDefinitionReaderUtils 建立,如下:

  1.    public static AbstractBeanDefinition createBeanDefinition(

  2.            @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

  3.        GenericBeanDefinition bd = new GenericBeanDefinition();

  4.        bd.setParentName(parentName);

  5.        if (className != null) {

  6.            if (classLoader != null) {

  7.                bd.setBeanClass(ClassUtils.forName(className, classLoader));

  8.            }

  9.            else {

  10.                bd.setBeanClassName(className);

  11.            }

  12.        }

  13.        return bd;

  14.    }

該方法主要是設定 parentName 、className、classLoader。

建立完 GenericBeanDefinition 實體後,再呼叫 parseBeanDefinitionAttributes(),該方法將建立好的 GenericBeanDefinition 實體當做引數,對 Bean 標簽的所有屬性進行解析,如下:

  1.    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,

  2.                                                                @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {

  3.        // 解析 scope 標簽

  4.        if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {

  5.            error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);

  6.        }

  7.        else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {

  8.            bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));

  9.        }

  10.        else if (containingBean != null) {

  11.            // Take default from containing bean in case of an inner bean definition.

  12.            bd.setScope(containingBean.getScope());

  13.        }

  14.        // 解析 abstract 標簽

  15.        if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {

  16.            bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));

  17.        }

  18.        // 解析 lazy-init 標簽

  19.        String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);

  20.        if (DEFAULT_VALUE.equals(lazyInit)) {

  21.            lazyInit = this.defaults.getLazyInit();

  22.        }

  23.        bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

  24.        // 解析 autowire 標簽

  25.        String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);

  26.        bd.setAutowireMode(getAutowireMode(autowire));

  27.        // 解析 depends-on 標簽

  28.        if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {

  29.            String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);

  30.            bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));

  31.        }

  32.        // 解析 autowire-candidate 標簽

  33.        String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);

  34.        if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {

  35.            String candidatePattern = this.defaults.getAutowireCandidates();

  36.            if (candidatePattern != null) {

  37.                String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);

  38.                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));

  39.            }

  40.        }

  41.        else {

  42.            bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));

  43.        }

  44.        // 解析 primay 標簽

  45.        if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {

  46.            bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));

  47.        }

  48.        // 解析 init-method 標簽

  49.        if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {

  50.            String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);

  51.            bd.setInitMethodName(initMethodName);

  52.        }

  53.        else if (this.defaults.getInitMethod() != null) {

  54.            bd.setInitMethodName(this.defaults.getInitMethod());

  55.            bd.setEnforceInitMethod(false);

  56.        }

  57.        // 解析 destroy-mothod 標簽

  58.        if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {

  59.            String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);

  60.            bd.setDestroyMethodName(destroyMethodName);

  61.        }

  62.        else if (this.defaults.getDestroyMethod() != null) {

  63.            bd.setDestroyMethodName(this.defaults.getDestroyMethod());

  64.            bd.setEnforceDestroyMethod(false);

  65.        }

  66.        // 解析 factory-method 標簽

  67.        if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {

  68.            bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));

  69.        }

  70.        if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {

  71.            bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));

  72.        }

  73.        return bd;

  74.    }

從上面程式碼我們可以清晰地看到對 Bean 標簽屬性的解析,這些屬性我們在工作中都或多或少用到過。

完成 Bean 標簽基本屬性解析後,會依次呼叫 parseMetaElements()、 parseLookupOverrideSubElements()、 parseReplacedMethodSubElements()對子元素 meta、lookup-method、replace-method 完成解析。下篇博文將會對這三個子元素進行詳細說明。

【死磕 Spring】----- IOC 之 獲取 Document 物件

【死磕 Spring】----- IOC 之 註冊 BeanDefinition

【死磕 Spring】----- IOC 之 獲取驗證模型

【死磕 Spring】----- IOC 之 Spring 統一資源載入策略

【死磕 Spring】----- IOC 之深入理解 Spring IoC

END

贊(0)

分享創造快樂

© 2024 知識星球   網站地圖