1. 程式人生 > >spring深入學習(七)IOC 之解析 bean 標籤:BeanDefinition

spring深入學習(七)IOC 之解析 bean 標籤:BeanDefinition

解析 bean 標籤的過程其實就是構造一個 BeanDefinition 物件的過程,<bean> 元素標籤擁有的配置屬性,BeanDefinition 均提供了相應的屬性,與之一一對應。所以我們有必要對 BeanDefinition 有一個整體的認識。

BeanDefinition

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

  • AttributeAccessor :定義了與其它物件的(元資料)進行連線和訪問的約定,即對屬性的修改,包括獲取、設定、刪除。
  • BeanMetadataElement:Bean 元物件持有的配置元素可以通過getSource() 方法來獲取。

BeanDefinition 整個結構如下圖:

springçbeançå建_第5å¼ å¾ç

我們常用的三個實現類有:ChildBeanDefinition、GenericBeanDefinition、RootBeanDefinition,三者都繼承 AbstractBeanDefinition。如果配置檔案中定義了父 <bean> 和 子 <bean> ,則父 <bean> 用 RootBeanDefinition表示,子 <bean>

 用 ChildBeanDefinition 表示,而沒有父 <bean> 的就使用RootBeanDefinition 表示。GenericBeanDefinition 為一站式服務類。AbstractBeanDefinition對三個子類共同的類資訊進行抽象。

解析 Bean 標籤

在 BeanDefinitionParserDelegate.parseBeanDefinitionElement() 中完成 Bean 的解析,返回的是一個已經完成對 <bean> 標籤解析的 BeanDefinition 例項。在該方法內部,首先呼叫 createBeanDefinition()

 方法建立一個用於承載屬性的 GenericBeanDefinition 例項,如下:

    protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
            throws ClassNotFoundException {
        return BeanDefinitionReaderUtils.createBeanDefinition(
                parentName, className, this.readerContext.getBeanClassLoader());
    }

委託 BeanDefinitionReaderUtils 建立,如下:

    public static AbstractBeanDefinition createBeanDefinition(
            @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setParentName(parentName);
        if (className != null) {
            if (classLoader != null) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            }
            else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }

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

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

    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                                                                @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) {
        // 解析 scope 標籤
        if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
            error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
        }
        else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
            bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
        }
        else if (containingBean != null) {
            // Take default from containing bean in case of an inner bean definition.
            bd.setScope(containingBean.getScope());
        }

        // 解析 abstract 標籤
        if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
            bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
        }

        // 解析 lazy-init 標籤
        String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
        if (DEFAULT_VALUE.equals(lazyInit)) {
            lazyInit = this.defaults.getLazyInit();
        }
        bd.setLazyInit(TRUE_VALUE.equals(lazyInit));

        // 解析 autowire 標籤
        String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
        bd.setAutowireMode(getAutowireMode(autowire));

        // 解析 depends-on 標籤
        if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
            String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
            bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
        }

        // 解析 autowire-candidate 標籤
        String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
        if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
            String candidatePattern = this.defaults.getAutowireCandidates();
            if (candidatePattern != null) {
                String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
            }
        }
        else {
            bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
        }

        // 解析 primay 標籤
        if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
            bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
        }

        // 解析 init-method 標籤
        if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
            String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
            bd.setInitMethodName(initMethodName);
        }
        else if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }

        // 解析 destroy-mothod 標籤
        if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
            String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
            bd.setDestroyMethodName(destroyMethodName);
        }
        else if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }

        // 解析 factory-method 標籤
        if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
            bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
        }
        if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
            bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
        }

        return bd;
    }

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

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