美文网首页Spring源码
BeanDefinition 在IOC的解析和注册

BeanDefinition 在IOC的解析和注册

作者: KingdomCoder | 来源:发表于2020-04-29 00:53 被阅读0次
概述

前面我们介绍了BeanDefinition的载入和解析的过程,将我们定义好的Bean资源文件载入并转换成了Document对象,然后Document对象通过BeanDefinitionDocumentReader来解析,这些动作完成以后,用户自定义的BeanDefinition信息已经在IOC容器内建立起了自己的数据结构,以及相应的数据表示,但这些数据还不能在IOC容器中直接使用,需要在IOC容器中对这些BeanDefinition进行注册。这个注册为IOC容器提供了更友好的使用方式。在DefaultListableBeanDactory中是使用一个Map对象载入并持有这些BeanDefinition的,代码如下所示:

    /** Map of bean definition objects, keyed by bean name. */
    /**持有BeanDefinition的map容器**/
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
源码解析

1.核心流程时序图:

核心流程时序图
从源码实现的角度我们可以分析得到上图的调用关系。我们可以跟踪源码具体看一下注册实现,在DefaultListableBeanFactory中实现了BeanDefinitionRegistry的接口,这个接口的实现完成了BeanDefinition向容器注册。注册过程就是将解析得到的BeanDefinition设置到Map中去,但是如果遇到同名的BeanDefinition,进行处理的时候需要依据allowBeanDefinitionOverriding的配置来完成。下面我们就BeanDefinition的注册逻辑展开分析。

2.源代码分析

  • registerBeanDefinitions核心流程代码解析:

    
    /**
     * 通过解析Document解析注册BeanDefinition
     * Register the bean definitions contained in the given DOM document.
     * Called by {@code loadBeanDefinitions}.
     * <p>Creates a new instance of the parser class and invokes
     * {@code registerBeanDefinitions} on it.
     * @param doc the DOM document
     * @param resource the resource descriptor (for context information)
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of parsing errors
     * @see #loadBeanDefinitions
     * @see #setDocumentReaderClass
     * @see BeanDefinitionDocumentReader#registerBeanDefinitions
     */
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 获取BeanDefinition的Document解析器
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        // 获取已经注册的BeanDefinition的个数
        int countBefore = getRegistry().getBeanDefinitionCount();
        // 创建XmlRederContext,解析Document并注册BeanDefinition
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        // 计算新注册的BeanDefinition的数量
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    
  • registerBeanDefinitions的处理逻辑解析:

    /**
     * This implementation parses bean definitions according to the "spring-beans" XSD (or DTD, historically).
     * document中element的解析并注册BeanDefinition·
     * <p>Opens a DOM Document; then initializes the default settings
     * specified at the {@code <beans/>} level; then parses the contained bean definitions.
     */
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    
  • doRegisterBeanDefinitions处理逻辑解析

    
    /**
     * Register each bean definition within the given root {@code <beans/>} element.
     */
    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // 从<beans />配置中注册每一个bean,如果有嵌套的beans,那么递归执行这个方法。
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        // 在递归的时候,跟踪父级delegate,新的递归调用引用上个方法的delegate
        BeanDefinitionParserDelegate parent = this.delegate;
        //  创建 BeanDefinitionParserDelegate 对象,并进行设置到 delegate
        this.delegate = createDelegate(getReaderContext(), root, parent);
        // 检查 <beans /> 根标签的命名空间是否为空,或者是 http://www.springframework.org/schema/beans【1】
        if (this.delegate.isDefaultNamespace(root)) {
            // 处理 profile 属性。可参见《Spring3自定义环境配置 <beans profile="">》 【2】
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                // 判定环境参数是否满足,无效则不注册
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }
        // 解析前处理目前是空处理,可以继承,由子类去实现
        preProcessXml(root);
        // 解析xml为BeanDefinition并向容器注册生成的BeanDefinition【3】
        parseBeanDefinitions(root, this.delegate);
        // 解析后处理,目前为空执行,子类可继承处理
        postProcessXml(root);
        // 设置为最初的BeanDefinitionParserDelegate
        this.delegate = parent;
    }
    

    【1】 检查<beans /> 根标签的命名空间是否为空,或者是 http://www.springframework.org/schema/beans
    【2】检查beans标签的是否指定profile环境注册,若profile参数是不满足条件,则不注册
    【3】解析element(<beans />)下的<bean/>元素并注册到BeanDefinition的map容器中。
    说明:createDelegate方法执行主要是创建代理,然后代理首先初始化一些默认的属性,DocumentDefaultsDefinition是存储默认配置的对象:default-lazy-initdefault-mergedefault-autowiredefault-dependency-checkdefault-autowire-candidatesdefault-init-methoddefault-destroy-method

  • parseBeanDefinitions处理逻辑解析

    /**
     * Parse the elements at the root level in the document: "import", "alias", "bean".
     *
     * @param root the DOM root element of the document
     */
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        // 如果该节点使用默认命名空间,执行默认解析【1】
        if (delegate.isDefaultNamespace(root)) {
            // root节点下的子节点【2】
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    // 如果该节点使用默认命名空间,执行默认解析【3】
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    } else { // 如果该节点非默认命名空间,执行自定义解析【4】
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {// 如果根节点非默认命名空间,执行自定义解析【5】
            delegate.parseCustomElement(root);
        }
    }
    

    【1】如果该节点使用默认命名空间,执行默认解析
    【2】root节点下的子节点
    【3】如果该节点使用默认命名空间,执行默认解析
    【4】如果该节点非默认命名空间,执行自定义解析
    【5】如果该节点非默认命名空间,执行自定义解析

  • parseDefaultElement处理逻辑解析

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        // import标签
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
            //  alias 解析
        } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
            //bean 解析
        } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
            // beans元素解析
        } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            //递归解析beans
            doRegisterBeanDefinitions(ele);
        }
    }
    
  • processBeanDefinition处理逻辑解析

    /**
     * Process the given bean element, parsing the bean definition and registering it with the registry.
     */
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        // 委托BeanDefinition类的parseBeanDefinitionElement方法进行元素解析,返回Beandefinition 【1】
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            // 当返回的bdHolder 不为空的情况下,若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析.【2】
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                // 最终执行注册逻辑【3】
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            // 下发注册事件,通知相关的监听器,这个bean已经加载完成【4】
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
    

    【1】委托BeanDefinition类的parseBeanDefinitionElement方法进行元素解析,返回Beandefinition ,此时的bdHolder实例已经包含了我们配置文件中的各种属性了,例如 : class,name,id,alias
    【2】当返回的bdHolder 不为空的情况下,若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析.
    【3】最终执行BeanDefinition注册逻辑
    【4】下发注册事件,通知相关的监听器,这个bean已经加载完成

  • registryBeanDefinition的注册逻辑分析

    从代码上分析我们的registryBeanDefinition的最终执行是在是通过public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry),注册的过程是在解析xml过程中完成注册逻辑的。

    //---------------------------------------------------------------------
    // Implementation of BeanDefinitionRegistry interface
    //---------------------------------------------------------------------
    // 注册BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
           throws BeanDefinitionStoreException {
       // 校验 beanName 与 beanDefinition 非空
       Assert.hasText(beanName, "Bean name must not be empty");
       Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
       if (beanDefinition instanceof AbstractBeanDefinition) {
           try {
               // 【1】 校验BeanDefinition,这也是注册前的最后一次校验了,主要是对属性 methodOverrides 进行校验。
               ((AbstractBeanDefinition) beanDefinition).validate();
           } catch (BeanDefinitionValidationException ex) {
               throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                       "Validation of bean definition failed", ex);
           }
       }
       //【2】从缓存中获取指定beanName的 BeanDefinition,主要 判断bean name下是否已经注册过BeanDefinition
       BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
       //【3】如果改BenDefinition已经注册,如果不允许覆盖的话,则抛出异常
       if (existingDefinition != null) {
           if (!isAllowBeanDefinitionOverriding()) {
               throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
           }
           // 当前要注册的BeanDefinition的role 大于 已经注册过的BeanDefinition 打印info 日志
           else if (existingDefinition.getRole() < beanDefinition.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 + "]");
               }
           }
           // 当前要注册的BeanDefinition与已被覆盖的BeanDefinition不是一个对象,打印Debug日志信息
           else if (!beanDefinition.equals(existingDefinition)) {
               if (logger.isDebugEnabled()) {
                   logger.debug("Overriding bean definition for bean '" + beanName +
                           "' with a different definition: replacing [" + existingDefinition +
                           "] with [" + beanDefinition + "]");
               }
           }
           // 打印 trace日志信息
           else {
               if (logger.isTraceEnabled()) {
                   logger.trace("Overriding bean definition for bean '" + beanName +
                           "' with an equivalent definition: replacing [" + existingDefinition +
                           "] with [" + beanDefinition + "]");
               }
           }
           // 覆盖已经注册的bean信息
           this.beanDefinitionMap.put(beanName, beanDefinition);
       }
       // 【4】未注册执行注册逻辑
       else {
           // 判断Bean的创建阶段是否已经开启,开启的话需要对beanDefinitionMap进行线程保护
           if (hasBeanCreationStarted()) {
               // Cannot modify startup-time collection elements anymore (for stable iteration)
               // beanDefinitionMap为全局变量,加锁保护,防止创建阶段和注册阶段的并发问题
               synchronized (this.beanDefinitionMap) {
                   // 添加到BeanDefinition的map 容器中
                   this.beanDefinitionMap.put(beanName, beanDefinition);
                   // 添加BeanName到 beanDefinitionNames中去(beanDefinitionNames初始化限制了大小为256,所以变更的时候需要引入一个中间变量-主要是扩容问题)
                   List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                   // 更新最新的beanDefinitionNames
                   updatedDefinitions.addAll(this.beanDefinitionNames);
                   updatedDefinitions.add(beanName);
                   this.beanDefinitionNames = updatedDefinitions;
                   // 从 manualSingletonNames 移除 beanName
                   removeManualSingletonName(beanName);
               }
           } else {
               // Still in startup registration phase
               // 添加到 BeanDefinition 到 beanDefinitionMap 中。
               this.beanDefinitionMap.put(beanName, beanDefinition);
               // 添加 beanName 到 beanDefinitionNames 中
               this.beanDefinitionNames.add(beanName);
               //  从 manualSingletonNames 移除 beanName
               removeManualSingletonName(beanName);
           }
           this.frozenBeanDefinitionNames = null;
       }
       // 【5】重新设置beanName对应的缓存
       if (existingDefinition != null || containsSingleton(beanName)) {
           resetBeanDefinition(beanName);
       }
    }
    
    

    【1】对BeanDefinition进行校验,这也是注册过程中最后一次校验了,主要是针对AbstractBeanDefinitionmethodOverride属性进行校验。
    【2】根据beanName从缓存中获取BeanDefinition。
    【3】如果缓存中已经存在,则根据allowBeanDefinitionOverriding标签判断是否允许覆盖,如果不允许覆盖,则抛出BeanDefinitionStoreException异常。
    【4】若缓存中没有beanName 的BeanDefinition对象,则判断当前阶段是否已经开始了Bean的创建阶段,如果是则对仅限并发保护,对BeanDefinitionMap进行加锁并发控制。否则直接设置即可。
    【5】若缓存存在改beanName或者单例bean集合中存在该beanName,则调用#resetBeanDefinition(beanName)方法,充值BeanDefinition缓存。

    整个阶段的核心流程其实就是对beanDefinitionMap的操作,只要核心在于this.beanDefinitionMap.put(beanName, beanDefinition)方法,而BeanDefinition的存储其实就是定义了个map,key为beanName,value为BeanDefinition。

小结
BeanDefinition解析注册详细流程图
微信公众号

相关文章

网友评论

    本文标题:BeanDefinition 在IOC的解析和注册

    本文链接:https://www.haomeiwen.com/subject/rvlwwhtx.html