我是靠谱客的博主 漂亮刺猬,最近开发中收集的这篇文章主要介绍Spring解析及注册BeanDefinition,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

上一篇文章介绍了资源文件转为Document文件.
下面接着介绍doLoadBeanDefinitions中最核心的部分.如果说前面两篇文章都是介绍XML解析的准备阶段的话,那么registerBeanDefinitions()里面会进行真正的XML文件的解析.
把代码贴一遍

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

		try {
			Document doc = doLoadDocument(inputSource, resource);
			int count = registerBeanDefinitions(doc, resource);
			return count;
		}
		catch (Exception ex) {
			throw ex;
		}
	}

有时候我会把源码中的异常捕获或者日志等多余无关紧要的方法删掉.
进入registerBeanDefinitions方法:

	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	// 这里实例化的是DefaultBeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 记录统计前BeanDefinition的加载个数
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 加载及注册
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// 返回本次加载的BeanDefinition个数
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		// doc.getDocumentElement()	是document的root
		// 以便根据root再进行操作
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}
	protected void doRegisterBeanDefinitions(Element root) {
		// 专门处理解析
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);
		// 处理profile属性
		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					return;
				}
			}
		}
		// 解析前最后一次修改配置文件的地方,留给子类实现
		preProcessXml(root);
		// 解析处理
		parseBeanDefinitions(root, this.delegate);
		// 解析后处理,留给子类实现
		postProcessXml(root);

		this.delegate = parent;
	}

首先我们先来看一下PROFILE_ATTRIBUTE属性,其实平时我们在xml文件中使用profile属性并不是很常用.

<beans profile="dev">
	.....
</beans>
<beans profile="production">
	.....
</beans>

集成到Web环境中,在web.xml中加入以下代码:

<context-param>
	<param-name>Spring.profiles.active</param-name>
	<param-name>dev</param-name>
</context-param>

使用这个特性,就可以在配置文件中部署两套配置来适用于开发环境和生产环境.
代码中就是先获取beans节点是否定义了profile属性,如果定义了则需要到环境变量里去找,所以会先使用断言判断environment不能为空.因为profile可以通过一定的分隔符来定义多个,所以需要进行拆分,并且解析每个profile都是符合环境变量中所定义的.

解析并注册BeanDefinition
根据代码到parseBeanDefinitions(root, this.delegate)

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);
					}
					// 否则使用自定义命名空间解析
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		// 节点不是默认的命名空间怎使用自定义命名空间进行解析
		else {
			delegate.parseCustomElement(root);
		}
	}

到这里最初的代码

Beanfactory bf = new XmlBeanFactory(new ClassPathResource("spring.xml"))

就已经告一段落了,但是上面讲到Spring对于两种命名空间的节点的解析还没有介绍,在后面的章节里会继续分析.

最后

以上就是漂亮刺猬为你收集整理的Spring解析及注册BeanDefinition的全部内容,希望文章能够帮你解决Spring解析及注册BeanDefinition所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部