一起学SF框架系列5.7-模块Beans-BeanDefinition解析

news2024/9/30 1:28:46

开发人员按元数据规则定义了应用bean,了解SF如何根据定义解析成BeanDefiniton有助于深入理解框架实现。解析过程如下:

资源加载

从资源文件加载bean的元数据配置,实际过程如下图:
在这里插入图片描述
实际从指定的XML文件加载bean定义是从XmlBeanDefinitionReader.doLoadBeanDefinitions开始。

解析

解析就是两大步:
1、把资源文件内容通过SAX解析器解析成DOM文档
2、从DOM文档生成BeanDefinition
源代码(XmlBeanDefinitionReader.doLoadBeanDefinitions):

	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			//将资源解析成Document
			Document doc = doLoadDocument(inputSource, resource);
			//基于Document生成BeanDefinition
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (SAXParseException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
		}
		catch (SAXException ex) {
			throw new XmlBeanDefinitionStoreException(resource.getDescription(),
					"XML document from " + resource + " is invalid", ex);
		}
		catch (ParserConfigurationException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Parser configuration exception parsing XML from " + resource, ex);
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"IOException parsing XML document from " + resource, ex);
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(resource.getDescription(),
					"Unexpected exception parsing XML document from " + resource, ex);
		}
	}

资源文件到Document

Spring实现比较复杂,基本关系图如下:
在这里插入图片描述
主要是用SAX方式对xml格式元数据解析成DOM文档,同spring本身目的关系不大,不需详细跟踪代码,有兴趣同学可以自己学习了解。

Document到BeanDefinition

主要过程

在这里插入图片描述

XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource)

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		//生成DOM解析器(负责生成BeanDefinition)
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//返回已经注册在BeanFactory中的beanDefinitions数量(支持多个元数据配置文件)
		int countBefore = getRegistry().getBeanDefinitionCount();
		//生成BeanDefinition
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//返回本次beanDefinitions数量(BeanFactory现有数量-生成前记录的数量)
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

BeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)

一看就明。

	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

BeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root)

从bean根元素( )开始解析。

	//不理解怎么成deprecation
	@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
	protected void doRegisterBeanDefinitions(Element root) {
    	//保存BeanDefinitionParser代理
    	BeanDefinitionParserDelegate parent = this.delegate;
    	
    	//生成当前用的BeanDefinitionParser代理,初始化一些默认值
		this.delegate = createDelegate(getReaderContext(), root, parent);
		//默认命名空间是"http://www.springframework.org/schema/beans"
		if (this.delegate.isDefaultNamespace(root)) {
			//xml文件中沒有使用到"profile",有的话需要加载profile相关值 注1
			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;
				}
			}
		}

		//xml预处理(空实现)
		preProcessXml(root);
		//生成BeanDefinition,并注册到BeanFactory
		parseBeanDefinitions(root, this.delegate);
		//xml预处理(空实现)
		postProcessXml(root);

		//恢复BeanDefinitionParser代理
		this.delegate = parent;
	}

注1 什么是profile,参考:一起学SF框架系列6.2-模块core-Environment

BeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

生成BeanDefinition,并注册到BeanFactory。

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		//根节点是默认命名空间(http://www.springframework.org/schema/beans)解析 注1
		if (delegate.isDefaultNamespace(root)) {
			//获取根节点下所有子节点
			NodeList nl = root.getChildNodes();
			//逐一解析每个子节点
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element ele) {
					//每个子节点按命名空间对应解析器进行解析
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//非默认命名空间解析
			delegate.parseCustomElement(root);
		}
	}

注1:命名空间的理解如下,一个命名空间对应一个解析处理器:
如启用注解配置,需在spring的配置文件applicatinoContext.xml中加入下面这行:
<context:annotation-config />
意思是标签annotation-config属于命名空间context。context就对应一个解析处理器。解析的时候需先获取context对应解析处理器。解析处理器又会初始化一些解析器出來,一个解析器就对应着一個标签。
基于默认命名空间如何解析往下跟踪。

BeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)

默认命名空间的元素解析。

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);
    }
    
    //嵌套标签进入这个方法
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // 嵌套标签从doRegisterBeanDefinitions递归开始
        doRegisterBeanDefinitions(ele);
    }
}

基于生成bean往下跟踪。

BeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

把bean元素解析成BeanDefinition并注册到BeanFactory中。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   
    //把元素解析成BeanDefinition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {  
        //装饰beanDefinition
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            //注册BeanDefinition到工厂中
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                                     bdHolder.getBeanName() + "'", ele, ex);
        }
        
        // 发送组件(bean)注册事件
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele)

//把元素解析成BeanDefinition

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
    //获取元素id
    String id = ele.getAttribute(ID_ATTRIBUTE);
    
    //获取元素name
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    //记录元素alias
    List<String> aliases = new ArrayList<String>();
    
    /* id、name、alias关系处理 注1 */
    //name解析
    if (StringUtils.hasLength(nameAttr)) {
        //name属性对应的name值如果有分隔符MULTI_VALUE_ATTRIBUTE_DELIMITERS,那么切分成数组
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        //所有name都是别名
        aliases.addAll(Arrays.asList(nameArr));
    }
    //指定了id就用id值作为bean名称
    String beanName = id;
    //如果没有id,但是指定了name,就用name值作为bean名称
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        //拿第一个name值作为bean名称,其余的还是别名
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("No XML 'id' specified - using '" + beanName +
                         "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {        
        //检查bean名称和别名是否已经被使用了,如果用了就报错
        checkNameUniqueness(beanName, aliases, ele);
    }
    
    //解析beanDefinition本身
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {       
        //如果没有定义id、name、alias,自动生成beanName
        if (!StringUtils.hasText(beanName)) {
            try {
                //有containingBean
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                        beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    //无containingBean,用容器生成beanName
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null &&
                        beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                        !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        
                        //beanClassName同时作为别名
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Neither XML 'id' nor 'name' specified - " +
                                 "using generated bean name [" + beanName + "]");
                }
            }
            catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
            }
        }
        
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        //组装成完整beanDefinition返回
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

注1:了解bean的id、name、alias关系,参考:一起学SF框架系列5.1-模块Beans-bean概述

BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)

不关注bean的名称和别名,只解析BeanDefinition自身。

public AbstractBeanDefinition parseBeanDefinitionElement(
    Element ele, String beanName, BeanDefinition containingBean) {
    //解析的beanName进栈(主要考虑元素ele可能还嵌套有子元素,则后续放入子元素,到时子元素先弹出
    this.parseState.push(new BeanEntry(beanName));

    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        //如果有指定class属性,则拿到class属性值
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {           
        //如果有指定parent属性,则拿到parent属性值
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }

    try {       
        //创建BeanDefinition
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        
        //设置BeanDefinition属性
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        
        //如果有description子元素,设置到BeanDefinition中
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        
        //如果有Meta子元素,获取key和value属性,设置到BeanDefinition中
        parseMetaElements(ele, bd);
        
        //如果有lookup-method子元素,获取name和bean属性,设置到BeanDefinition中
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        
        //如果有replaced-method子元素,设置BeanDefinition 
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        
        //如果有constructor-arg子元素,设置BeanDefinition的构造方式
        parseConstructorArgElements(ele, bd);
        
        //解析bean的Property的属性设置到BeanDefinition中
        parsePropertyElements(ele, bd);
        
        //子元素qualifier处理
        parseQualifierElements(ele, bd);
        
        //设置定义来源
        bd.setResource(this.readerContext.getResource());
        
        //元素有Source
        bd.setSource(extractSource(ele));

        return bd;
    }
    catch (ClassNotFoundException ex) {
        error("Bean class [" + className + "] not found", ele, ex);
    }
    catch (NoClassDefFoundError err) {
        error("Class that bean class [" + className + "] depends on not found", ele, err);
    }
    catch (Throwable ex) {
        error("Unexpected failure during bean definition parsing", ele, ex);
    }
    finally {
        //解析完成出栈
        this.parseState.pop();
    }

    return null;
}

BeanDefinitionParserDelegate.createBeanDefinition(@Nullable String className, @Nullable String parentName)

创建BeanDefinition并设置属性:parentName和beanClassName

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

/**
* 此方法是BeanDefinitionReaderUtils的静态方法
*/
public static AbstractBeanDefinition createBeanDefinition(
    String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
	//new通用BeanDefinition
    GenericBeanDefinition bd = new GenericBeanDefinition();
    bd.setParentName(parentName);
    if (className != null) {
        if (classLoader != null) {
            //有classLoader,就导入Class
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }
        else {          
            //无classLoader,只设置BeanClassName
            bd.setBeanClassName(className);
        }
    }
    return bd;
}

BeanDefinitionParserDelegate.parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd)

解析bean定义设置到BeanDefinition属性

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                                                            BeanDefinition containingBean, AbstractBeanDefinition bd) {
    
    //有singleton属性报错(新的用scope代替)
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }    
    //如果有scope配置
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    else if (containingBean != null) {
        // 按containingBean的Scope设置
        bd.setScope(containingBean.getScope());
    }
    
    //是否有abstract属性
    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }

    //设置lazyInit属性(如果没有设置则为默认值)
    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); //非TRUE_VALUE则为false
    
    //设置autowire属性
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));
    
    //设置依赖检查属性
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
    
    //设置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));
    }
    
    //设置primary属性
    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);
        if (!"".equals(initMethodName)) {
            bd.setInitMethodName(initMethodName);
        }
    }
    else {
        //没有init-method属性,设置默认InitMethod
        if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }
    }
    
    //设置destroy-method属性
    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    }
    else {
        //没有destroy-method属性,设置默认DestroyMethod
        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));
    }
    
    //设置factory-bean属性
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }

    return bd;
}

BeanDefinitionParserDelegate.parsePropertyElements(Element beanEle, BeanDefinition bd)

解析bean的属性值property。

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            //元素为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("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    
    //解析property元素进栈
    this.parseState.push(new PropertyEntry(propertyName));
    
    try {
        //propertyName不能重复name
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        
        //具体解析property元素属性
        Object val = parsePropertyValue(ele, bd, propertyName);
        
        //生成PropertyValue(propertyName:value)
        PropertyValue pv = new PropertyValue(propertyName, val);
        
        //ele有meta子元素,获取meta的key和value属性,设置到PropertyValue中
        parseMetaElements(ele, pv);
        
        pv.setSource(extractSource(ele));
        
        //将PropertyValue添加到BeanDefinition中
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {      
        //解析property元素出栈
        this.parseState.pop();
    }
}

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
   
    //如果propertyName为null,则是constructor-arg元素
    String elementName = (propertyName != null) ?
        "<property> element for property '" + propertyName + "'" :
    "<constructor-arg> element";
    
    //Property下面都应该只有一个子标签: ref, value, list等.
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
            !nodeNameEquals(node, META_ELEMENT)) {
            //除开description和meta标签,子标签最多只能有一个
            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);
    
    //value和ref属性不能同时存在;如果有子元素,则value和ref都不能存在,否则报错
    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是ref的不可变占位符类,实际在运行时解析为真正的bean引用实例
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
    }
    //元素属性是value的情况
    else if (hasValueAttribute) {
    	//valueHolder存储String值和目标类型。实际的转换将由BeanFactory执行
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    }
    else if (subElement != null) {
	    //子元素处理
        return parsePropertySubElement(subElement, bd);
    }
    else {
        //没指定ref或者value或者子元素,返回null
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}

//过渡方法
public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
    return parsePropertySubElement(ele, bd, null);
}

//解析property或者constructor-arg标签的子标签,可能为value, ref或者集合
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    //如果ele不属于默认命名空间
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        //如果ele是bean类型,嵌套bean处理
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    else if (nodeNameEquals(ele, REF_ELEMENT)) {
	    //如果ele是ref元素类型
        String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
        boolean toParent = false;
		if (!StringUtils.hasLength(refName)) {
			// A reference to the id of another bean in a parent context.
			//是对父容器中另一个bean id的引用
			refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
			toParent = true;
			if (!StringUtils.hasLength(refName)) {
				error("'bean' or 'parent' is required for <ref> element", ele);
				return null;
			}
		}
        if (!StringUtils.hasText(refName)) {
            error("<ref> element contains empty target attribute", ele);
            return null;
        }
        //生成引用占位类
        RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
        ref.setSource(extractSource(ele));
        return ref;
    }
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
	    //如果是idref引用
        return parseIdRefElement(ele);
    }
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
	    //如果是value元素
        return parseValueElement(ele, defaultValueType);
    }
    else if (nodeNameEquals(ele, NULL_ELEMENT)) {
	    //如果是null元素,用null做值处理
        TypedStringValue nullHolder = new TypedStringValue(null);
        nullHolder.setSource(extractSource(ele));
        return nullHolder;
    }
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
	    //如果是array元素
        return parseArrayElement(ele, bd);
    }    
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
	    //如果是list元素
        return parseListElement(ele, bd);
    }
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
	    //如果是set元素
        return parseSetElement(ele, bd);
    }
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
	    //如果是map元素
        return parseMapElement(ele, bd);
    }    
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
	    //如果是props元素
        return parsePropsElement(ele);
    }
    else {
	    //以上都不是,报错
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}

每种类型元素的解析简单,不再继续跟踪。

BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef)

按需装饰BeanDefinition。

//过渡方法
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
    return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}

//真正装饰BeanDefinition实现
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
    Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {

    BeanDefinitionHolder finalDefinition = definitionHolder;

    // Decorate based on custom attributes first.
    // 基于属性进行
    NamedNodeMap attributes = ele.getAttributes();
    for (int i = 0; i < attributes.getLength(); i++) {
        Node node = attributes.item(i);
        finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    }

    // Decorate based on custom nested elements.
    // 基于嵌套元素进行
    NodeList children = ele.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
    }
    return finalDefinition;
}
//装饰处理
public BeanDefinitionHolder decorateIfRequired(
			Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

		String namespaceUri = getNamespaceURI(node);
		/*显然,默认命名空间的是不需要装饰的;值装饰非默认命名空间的bean*/
		if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
			//获取非默认命名空间的处理器
			NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
			if (handler != null) {
				//装饰处理
				BeanDefinitionHolder decorated =
						handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
				if (decorated != null) {
					return decorated;
				}
			}
			else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
				error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
			}
			else {
				// A custom namespace, not to be handled by Spring - maybe "xml:...".
				if (logger.isDebugEnabled()) {
					logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
				}
			}
		}
		return originalDef;
	}

BeanDefinitionReaderUtils.registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

注册BeanDefinition到容器的BeanFactory

public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {
    // 用beanName 注册 BeanDefinition
    String beanName = definitionHolder.getBeanName();  
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    //注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

说明:registry实际是BeanFactory,registry.registerBeanDefinition和registry.registerAlias实现在DefaultListableBeanFactory,比较简单就不再跟踪。

到此BeanDefinition如何解析跟踪完成,如何使用参见:一起学SF框架系列5.7-模块Beans-BeanDefinition使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/737291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑pdf如何转换成word格式?分享这三个方法给大家!

记灵在线工具是一个非常方便的PDF转Word工具&#xff0c;它可以帮助用户快速、准确地将PDF文件转换为Word格式。以下是使用步骤&#xff1a; 打开您的网络浏览器&#xff0c;访问记灵在线工具的官方网站。 在首页上找到并点击“PDF转Word”选项。 在新打开的页面中&#xff0…

如何在 SwiftUI 中配置 SwiftData

文章目录 前言创建模型模式和版本控制迈出关键的一步创建迁移计划创建模型容器从视图中查询模型从视图中访问模型上下文总结 前言 在 WWDC 2023 上&#xff0c;Apple 宣布了一个备受期待的新持久性刷新&#xff0c;以一种新的框架形式出现&#xff1a;SwiftData。SwiftData 从…

【设计模式】设计模式前置知识:UML类图入门

UML类图 介绍 UML–Unified modeling language UMl(统一建模语言)&#xff0c;是一种用于软件系统分析和设计的语言工具&#xff0c;它用于帮助软件开发人员进行思考和记录思路的结果UML本身是一套符号的规定&#xff0c;就像数学符号和化学符号一样&#xff0c;这些符号用于…

来啦!OceanBase 第7期技术征文活动获奖名单公布!

“小鱼”的诞生与成长离不开广大开发者的陪伴与支持&#xff0c;我们非常兴奋能把 4.1 版本的这一系列新能力带给大家&#xff0c;“小鱼”会游得更快更远&#xff0c;也会陪伴更多数据库开发者一同成长。 OceanBase 联合墨天轮技术社区&#xff0c;举行「4.1 上手体验」第五届…

基于SpringBoot+Hadoop+Vue的企业网盘系统

完整资料进入【数字空间】查看——baidu搜索"writebug" 1.1.1 选题的背景 随着信息网络技术的迅猛发展&#xff0c;云计算技术从它的概念提出已经开始在实际生产环境中使用了。大部分的东西都已经慢慢云端化&#xff0c;这种新型的技术也受到许多互联网人员的关注&a…

初阶C语言——三子棋

我们今天讲一个小游戏&#xff0c;三子棋大家应该都玩过吧&#xff0c;就是行和列&#xff0c;或者对角线上有一样大的字符时&#xff0c;就为获胜&#xff0c;今天我们就来写这样的一个代码实现这样的功能 首先我们要创建两个源文件和一个头文件 头文件game.h用来包含我们的头…

EmEditor制表符设置为空格

以下是具体操作 工具 - 当前配置属性 - 常规 - 制表符/缩进 - 将制表符转换为空格 前打对钩

作业怎么清除试卷笔迹?拿捏可以擦除答案的方法

在日常学习中&#xff0c;我们经常会遇到需要修改或擦除试卷上的笔迹的情况。本文将介绍一种简单实用的方法&#xff0c;即使用手机拍照扫描试卷并擦除答案。 手机拍照扫描试卷 首先&#xff0c;我们需要使用手机拍照扫描试卷。这一步非常简单&#xff0c;只需要将试卷平铺在桌…

集成学习-BaggingVoting和多个模型的混淆矩阵

当涉及到集成学习时&#xff0c;投票法和袋装法是两种常见的技术&#xff0c;用于将多个基学习器&#xff08;base learner&#xff09;组合成一个强大的集成模型。 投票法&#xff08;Voting&#xff09;&#xff1a;投票法是一种简单且常用的集成学习方法。在投票法中&#…

Django_设置和读取cookie

设置cookie 在响应对象中使用set_cookie方法设置cookie from django.http import HttpResponsedef set_cookie(request):rsp HttpResponse("set cookie")rsp.set_cookie("set_cookie", "hello python", max_age3600)return rsp 注&#xff1…

Latex更改字体颜色以及快速生成 SCI 论文的 revised version 和 pure version

记录一下如何更改 Latex 字体颜色&#xff0c;在返修 SCI 论文时&#xff0c;如何较为快捷地完成 revised version 和 pure version 两个不同版本修改稿件的编辑与生成。 更改字体颜色 导入宏包 在 LaTeX 中&#xff0c;使用 \textcolor 命令或 \color 命令可以改变文本的颜…

十大机器学习算法之一:线性回归

十大机器学习算法之一&#xff1a;线性回归 1 知识预警1.1 线性代数1.2 矩阵微积分 2 什么是回归分析&#xff1f;3 线性回归3.1 一元线性回归3.2 多元线性回归 4 多项式回归 1 知识预警 1.1 线性代数 ( A T ) T A (A^\mathrm{T})^\mathrm{T}A (AT)TA$ ( A B ) T A T B T…

OpenHarmony社区运营报告(2023年6月)

本月快讯 • 6月12日&#xff0c;以“OpenHarmony共建开放&#xff0c;共享未来”为主题的2023开放原子全球开源峰会OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;分论坛在北京北人亦创国际会展中心第一报告厅圆满落幕&#xff0c;根深叶茂&#xff0c…

【Java】面向对象编程 面向对象基础

一、面向对象基础 面向对象编程&#xff0c;是一种通过对象的方式&#xff0c;把现实世界映射到计算机模型的一种编程方法。 现实世界中&#xff0c;我们定义了“人”这种抽象概念&#xff0c;而具体的人则是“小明”、“小红”、“小军”等一个个具体的人。所以&#xff0c;…

uni-app 从零开始第三章:底部 tabBar

pages.json 页面路由 | uni-app官网 一、新建 home页面 找到pages目录&#xff0c;新增一个home的页面&#xff0c;勾选上同时新建文件夹 新建完成后&#xff0c;pages.json 中 会自动添加上刚刚新建的文件信息 二、新增tabBar数据 在 pages.json中新增以下代码 "tabB…

基于pyqt5实现一款简单的界面软件(radioButton、comboBox、pushButton、图片显示)

pyqt5使用记录涉及pyqt界面控件的基本介绍&#xff0c;使用designer设计界面ui&#xff0c;并将其转化为py代码。关于界面主要实现radioButton的互斥选中事件、comboBox的选中事件&#xff08;依据list添加item&#xff09;、pushButton的单击事件、槽函数自动绑定、图片的拖入…

嵌入式开发之上位机工业风界面实现

在做测控类的嵌入式系统开发时&#xff0c;一个精美的上位机控制软件UI是可以为系统增色不少&#xff0c;一般会采用组态软件来开发&#xff0c;我们来看看下面的界面 是不是非常直观有工业质感&#xff0c;还可以根据实时数据进行动态的显示和动画效果&#xff0c;那这些炫酷的…

自定义切换整行上下位置快捷键

自定义切换整行上下位置快捷键 在File菜单中选择Settings选项&#xff0c;搜索move li 先删掉原来的快捷键 再添加你要设置的快捷键 确认就可以了。

word转Markdown文件的几个方法

word转Markdown文件的几个方法 1、 安装writage 软件&#xff0c;但是writage 需要收费了。 如果只是markdown文本编辑&#xff0c;可以直接安装typora来。 2. 利用Pandoc软件来转换word文件到markdown文件 注意doc文件需要保存docx文件格式才可以使用下面命令行 pandoc &q…

C++多线程学习(十六、STL算法中的并行版本,sequenced_policy)

目录 sequenced_policy 使用代码&#xff1a; 准备 代码 结果&#xff1a; sequenced_policy 增加参数:sequenced_policy提供相应并行版算法 execution::seq并行算法执行可以不并行化execution::par并行算法执行可以并行化execution::par_unseq并行算法执行的可以并行以…