SpringIOC源码阅读—BeanDefinitionDocu
BeanDefinitionDocumentReader的作用,通过命名后缀就可以推断出它的职责是解析文件然后调用生成BeanDefinition的接口完成注册。
我们来看它的doRegisterBeanDefinitions
(注册bean)方法:
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
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;
}
核心步骤我已经加上了注释,其中parseBeanDefinitions(root, this.delegate)
方法中root就是xml文件的实例,我们跟进去
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
//是否是DefaultNamespace
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);
}
}
这段代码上来就判断是否是默认的Namespace,根据断点可以看到root的Namespace是http://www.springframework.org/schema/beans
,对比一下beans.xml
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="user" class="xz.quartz.analysis.User"></bean>
</beans>
这个是beans的xmlns属性的值,这个我们先跳过继续往后读可以看到是循环解析Node的过程,也就是解析bean节点,继续看第二个注释,跟进去
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)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
瞬间豁然开朗这里的判断通俗易懂,就是根据不同的标签类型分而治之。其中import标签、bean标签、beans标签想必大家都遇见过。
我们这次是注册的bean标签,所以程序会进入bean的处理:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//这里通过delegate拿到了bean实例
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//注册最终的bean实例
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这段代码我们可以看到Spring是通过BeanDefinitionParserDelegate拿到bean对象的实例然后完成注册的,我们下篇文章讲的就是这个过程。
接下来我们聊一下上面留下的一个问题,Namespace的值是http://www.springframework.org/schema/beans
也就是beans的xmlns属性的值,所以才会分上面import标签、bean标签、beans标签来分别处理。
也就是意味着我们可以自定义标签去解析,去处理,这也证明了Spring扩展性是毋庸置疑的,bean生成的过程是可插拔的。这个特性也是对一个框架最基本的要求