BeanDefinition 在IOC的解析和注册(八)

概述

前面我们介绍了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解析注册详细流程图
微信公众号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值