Spring源码解析 -- 读取bean元数据

Spring源码解析 -- 读取bean元数据
spring源码解析 -- 构造bean
spring源码解析 -- 注入属性
spring源码解析 -- Spring Context
Spring源码解析 -- AOP原理(1)
Spring源码解析 -- AOP原理(2)
Spring源码解析 -- SpringMvc原理java

源码分析基于spring 4.3.xnode

本文经过阅读源码,分析spring如何读取xml配置中的bean元数据。
关于阅读源码的思路,可参考 -- 如何阅读java源码 spring

本文主要分析XmlBeanFactory,XmlBeanFactory是一个简单的容器, 从XML文件中读取配置元数据。安全

BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
复制代码

XmlBeanFactory已过期,但好在简单,便于分析源码。bash

XmlBeanFactory#构造函数 -> XmlBeanDefinitionReader#loadBeanDefinitions -> XmlBeanDefinitionReader#doLoadBeanDefinitions微信

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {
	try {
		Document doc = doLoadDocument(inputSource, resource);	// #1
		return registerBeanDefinitions(doc, resource);	// #2
	}
	...
}
复制代码

#1 加载xml到Document类(使用org.w3c.dom读取xml文件) #2 registerBeanDefinitions -> 解析xml数据dom

XmlBeanDefinitionReader#registerBeanDefinitionside

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();	// #1
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));	// #2
	return getRegistry().getBeanDefinitionCount() - countBefore;
}
复制代码

#1 构建BeanDefinitionDocumentReader
#2 createReaderContext -> 构建ReaderContext,ReaderContext中存放了xml的resource,XmlBeanDefinitionReader等信息,这些后面都要使用。
registerBeanDefinitions -> 使用BeanDefinitionDocumentReader解析xml数据函数

注意,ReaderContext中存放了XmlBeanDefinitionReader,而XmlBeanDefinitionReader中存放了bean注册器BeanDefinitionRegistry(后面注册BeanDefinition要使用)。这个注册器就是XmlBeanFactory,XmlBeanFactory中构建XmlBeanDefinitionReader时将this做为Registry参数 XmlBeanDefinitionReader#reader源码分析

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
复制代码

XmlBeanFactory的父类DefaultListableBeanFactory实现了BeanDefinitionRegistry。

DefaultBeanDefinitionDocumentReader#registerBeanDefinitions -> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
	BeanDefinitionParserDelegate parent = this.delegate;
	this.delegate = createDelegate(getReaderContext(), root, parent);

	if (this.delegate.isDefaultNamespace(root)) {	// #1
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);	// #2
		if (StringUtils.hasText(profileSpec)) {	 
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				if (logger.isInfoEnabled()) {
					logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
							"] not matching: " + getReaderContext().getResource());
				}
				return;
			}
		}
	}

	preProcessXml(root);	// #3
	parseBeanDefinitions(root, this.delegate);	// #4
	postProcessXml(root);

	this.delegate = parent;
}
复制代码

#1 判断元素的命名空间是否为spring的beans空间,这个方法后面也有使用
#2 处理PROFILE元素属性
#3 预处理,为子类提供的扩展方法
#4 parseBeanDefinitions -> 解析beans元素

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	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) {
				Element ele = (Element) node;
				if (delegate.isDefaultNamespace(ele)) {	
					parseDefaultElement(ele, delegate);	// #1
				}
				else {
					delegate.parseCustomElement(ele);	// #2
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}
复制代码

#1 对于beans命名空间的元素,使用默认的方法进行解析
#2 处理非beans命名空间的元素,使用对应的解析器处理
用户也能够自定义标签及标签解析器。

DefaultBeanDefinitionDocumentReader#parseDefaultElement

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {	// #1
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {	// #2
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {	// #3
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {	// #4
			doRegisterBeanDefinitions(ele);
		}
	}
复制代码

#1 解析import元素
#2 解析alias元素
#3 解析bean元素
#4 解析beans元素

主要看对bean元素的解析,DefaultBeanDefinitionDocumentReader#processBeanDefinition

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);	// #1
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);	// #2
			try {
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());	// #3
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));	// #4
		}
	}
复制代码

#1 根据xmleizo,生成BeanDefinitionHolder
#2 应用NamespaceHandler#decorate扩展方法
#3 将BeanDefinition注册到spring上下文
#4 发送注册事件

这里出现了一个很重要的类BeanDefinition。

BeanDefinition是spring对bean元数据的抽象, 是配置文件中<bean>元素在spring容器中的内部表示类,存储了bean的元数据, 如属性PropertyValues, BeanClassName,Scope等。
BeanDefinitionHolder中持有BeanDefinition实例,以及beanName和aliases属性。

构造BeanDefinition

BeanDefinitionParserDelegat#parseBeanDefinitionElement有几个重载方法,最终都调用以下方法

public AbstractBeanDefinition parseBeanDefinitionElement(
		Element ele, String beanName, BeanDefinition containingBean) {

	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {	
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}

	try {
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {	
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}
		AbstractBeanDefinition bd = createBeanDefinition(className, parent); // #1

		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);	// #2
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));	

		parseMetaElements(ele, bd);	// #3
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());	// #4
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());	// #5

		parseConstructorArgElements(ele, bd);	// #6
		parsePropertyElements(ele, bd);	// #7
		parseQualifierElements(ele, bd);	// #8

		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));

		return bd;
	}
	...
}
复制代码

#1 使用className和parent建立BeanDefinition
#2 处理scope等元素属性
#3 处理meta元素属性
#4 处理lookup-method元素属性
#5 处理replaced-method元素属性
#6 处理constructor-arg构造方法参数
#7 处理property元素
#8 处理qualifier元素

看一下如何处理property元素 BeanDefinitionParserDelegate#parsePropertyElements -> BeanDefinitionParserDelegate#parsePropertyElement

public void parsePropertyElement(Element ele, BeanDefinition bd) {
	String propertyName = ele.getAttribute(NAME_ATTRIBUTE);	// #1
	if (!StringUtils.hasLength(propertyName)) {
		error("Tag 'property' must have a 'name' attribute", ele);
		return;
	}
	this.parseState.push(new PropertyEntry(propertyName));
	try {
		if (bd.getPropertyValues().contains(propertyName)) {
			error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
			return;
		}
		Object val = parsePropertyValue(ele, bd, propertyName);	// #2
		PropertyValue pv = new PropertyValue(propertyName, val);	// #3
		parseMetaElements(ele, pv);
		pv.setSource(extractSource(ele));
		bd.getPropertyValues().addPropertyValue(pv);	// #4
	}
	finally {
		this.parseState.pop();
	}
}
复制代码

#1 解析属性名
#2 将xml配置的属性值转化为内部表示类
#3 建立PropertyValue,PropertyValue中name存放属性名,value存放了xml配置原始值。
#4 添加到BeanDefinition,BeanDefinition使用MutablePropertyValues存放全部的属性信息。
xml配置原始值并非属性最终值,而是xml配置在spring中对应的内部表示类,如property元素的value属性会表示为TypedStringValue(相似于BeanDefinition表示<bean>元素)。

BeanDefinitionParserDelegate#parsePropertyValue

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
	...

	boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
	boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
	if ((hasRefAttribute && hasValueAttribute) ||
			((hasRefAttribute || hasValueAttribute) && subElement != null)) {
		error(elementName +
				" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
	}

	if (hasRefAttribute) {	// #1
		String refName = ele.getAttribute(REF_ATTRIBUTE);
		if (!StringUtils.hasText(refName)) {
			error(elementName + " contains empty 'ref' attribute", ele);
		}
		RuntimeBeanReference ref = new RuntimeBeanReference(refName);
		ref.setSource(extractSource(ele));
		return ref;
	}
	else if (hasValueAttribute) {	// #2
		TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
		valueHolder.setSource(extractSource(ele));
		return valueHolder;
	}
	else if (subElement != null) {	// #3
		return parsePropertySubElement(subElement, bd);
	}
	else {
		// Neither child element nor "ref" or "value" attribute found.
		error(elementName + " must specify a ref or value", ele);
		return null;
	}
}
复制代码

#1 若是property元素存在ref属性,解析为RuntimeBeanReference
#2 若是存在value属性,解析为TypedStringValue
#3 若是存在子标签,就解析子标签。子标签和spring内部表示类对应以下
子标签为bean,解析为BeanDefinitionHolder
子标签为ref,解析为RuntimeBeanReference
子标签为idref,解析为RuntimeBeanNameReference
子标签为value,解析为TypedStringValue
子标签为null,解析为TypedStringValue
子标签为array,解析为ManagedArray
子标签为list,解析为ManagedList
子标签为set,解析为ManagedSet
子标签为map,解析为ManagedMap
子标签为props,解析为ManagedProperties

注册

回到DefaultBeanDefinitionDocumentReader#processBeanDefinition方法#3步骤, 看一下如何将BeanDefinition注册到spring上下文 BeanDefinitionReaderUtils#registerBeanDefinition

public static void registerBeanDefinition(
		BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
		throws BeanDefinitionStoreException {
	
	String beanName = definitionHolder.getBeanName();
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());	// #1

	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);	// #2
		}
	}
}		
复制代码

#1 使用beanName注册bean
#2 注册别名alias

注册器registry从ReaderContext中获取,实际就是DefaultListableBeanFactory(注意上文对ReaderContext的说明)。
DefaultListableBeanFactory#registerBeanDefinition

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
		throws BeanDefinitionStoreException {
	...
	BeanDefinition oldBeanDefinition;

	oldBeanDefinition = this.beanDefinitionMap.get(beanName);
	if (oldBeanDefinition != null) {
		...
	}
	else {
		if (hasBeanCreationStarted()) {	// #1
			synchronized (this.beanDefinitionMap) {	// #2
				this.beanDefinitionMap.put(beanName, beanDefinition);	// #3
				List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;	// #4
				if (this.manualSingletonNames.contains(beanName)) {
					Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
					updatedSingletons.remove(beanName);
					this.manualSingletonNames = updatedSingletons;	// #5
				}
			}
		}
		else {	// #6
			this.beanDefinitionMap.put(beanName, beanDefinition);
			this.beanDefinitionNames.add(beanName);
			this.manualSingletonNames.remove(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

	if (oldBeanDefinition != null || containsSingleton(beanName)) {
		resetBeanDefinition(beanName);
	}
}
复制代码

#1 判断spring是否进入构建bean的阶段
#2 beanDefinitionNames/manualSingletonNames不是线程安全类,须要加锁同步
#3 添加beanDefinition到DefaultListableBeanFactory#beanDefinitionMap
#4 经过写时复制,添加beanName到DefaultListableBeanFactory#beanDefinitionNames
#5 经过写时复制,删除manualSingletonNames的DefaultListableBeanFactory#beanDefinitionNames
#6 还在注册阶段,不须要加锁同步

最后, 看一下DefaultBeanDefinitionDocumentReader#parseBeanDefinitions方法#2步骤对非beans空间的xml标签的处理, BeanDefinitionParserDelegate#parseCustomElement

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
	String namespaceUri = getNamespaceURI(ele);
	NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);	// #1
	if (handler == null) {
		error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
		return null;
	}
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));	// #2
}
复制代码

#1 经过命名空间获取特定的NamespaceHandler #2 使用NamespaceHandler进行处理

若是您以为本文不错,欢迎关注个人微信公众号,您的关注是我坚持的动力!

相关文章
相关标签/搜索