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对于两种命名空间的节点的解析还没有介绍,在后面的章节里会继续分析.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值