基于XmlBeanFactory加载bean分析:parseDefaultElement(一)

DefaultBeanDefinitionDocumentReader.java
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)) {
                        //加载默认的阶段配置信息【程序入口】
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }

parseDefaultElement(ele, delegate)该方法会根据当前节点类型做三件事情

1、导入import

例如:

<import resource="applicationContext-mybean.xml"></import>

2、alias别名

<bean name="myBean,wahaha,gagBean" class="com.wolf.bean.Mybean1">
    <property name="name">
        <value>郑先生</value>
    </property>
    <property name="pwd">
        <value>666666888888</value>
    </property>
</bean>

<!--给myBean起别名-->
<alias name="myBean" alias="gagBean,gagaBean,gagagaBean"></alias>

3、bean定义

<bean name="myBean2" class="com.wolf.bean.Mybean1">
    <property name="name">
        <value>郑先生2</value>
    </property>
    <property name="pwd">
        <value>2222222</value>
    </property>
</bean>

4、beans集合

对于beans集合系统会重新走doRegisterBeanDefinitions处理流程,跟程序来源一样。

 

parseDefaultElement(ele, delegate)代码实现如下

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
	if(delegate.nodeNameEquals(ele, "import")) {//导入
		this.importBeanDefinitionResource(ele);
	} else if(delegate.nodeNameEquals(ele, "alias")) {//别名
		this.processAliasRegistration(ele);
	} else if(delegate.nodeNameEquals(ele, "bean")) {//bean
		this.processBeanDefinition(ele, delegate);
	} else if(delegate.nodeNameEquals(ele, "beans")) {//bean集合
		this.doRegisterBeanDefinitions(ele);
	}

}

一、import

protected void importBeanDefinitionResource(Element ele) {
	String location = ele.getAttribute("resource");
	if(!StringUtils.hasText(location)) {
		this.getReaderContext().error("Resource location must not be empty", ele);
	} else {
		location = this.getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
		LinkedHashSet actualResources = new LinkedHashSet(4);
		boolean absoluteLocation = false;

		try {
			absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
		} catch (URISyntaxException var11) {
			;
		}

		int actResArray;
		if(absoluteLocation) {
			try {
				actResArray = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
			} catch (BeanDefinitionStoreException var10) {
				this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
			}
		} else {
			try {
				Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
				//判断当前资源文件是否存在
				if(relativeResource.exists()) {
					//执行XmlBeanDefinitionReader的loadBeanDefinitions,跟加载资源的流程一致
					//所以import资源处理操作是非常简单的
					actResArray = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
					actualResources.add(relativeResource);
				} else {
					String baseLocation = this.getReaderContext().getResource().getURL().toString();
					actResArray = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
				}

			} catch (IOException var8) {
				this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
			} catch (BeanDefinitionStoreException var9) {
				this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
			}
		}
		
		
		Resource[] actResArray1 = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
		//这里做了一个事件通知
		this.getReaderContext().fireImportProcessed(location, actResArray1, this.extractSource(ele));
	}
}

二、alias别名解析

protected void processAliasRegistration(Element ele) {
	//通过当前节点的别名信息配置
	//name 表示BeanName
	String name = ele.getAttribute("name");
	//别名信息
	String alias = ele.getAttribute("alias");
	boolean valid = true;
	if(!StringUtils.hasText(name)) {
		this.getReaderContext().error("Name must not be empty", ele);
		valid = false;
	}

	if(!StringUtils.hasText(alias)) {
		this.getReaderContext().error("Alias must not be empty", ele);
		valid = false;
	}

	if(valid) {
		try {
			//XmlReaderContext-->BeanDefinitionRegistry-->GenericApplicationContext(接口BeanDefinitionRegistry)的registerAlias方法[DefaultListableBeanFactory beanFactory]
			//其实就是往DefaultListableBeanFactory beanFactory中设置别名信息(SimpleAliasRegistry为具体别名注册实现)
			//private final Map<String, String> aliasMap = new ConcurrentHashMap(16); 别名属性记录器
			this.getReaderContext().getRegistry().registerAlias(name, alias);
		} catch (Exception var6) {
			this.getReaderContext().error("Failed to register alias \'" + alias + "\' for bean with name \'" + name + "\'", ele, var6);
		}

		this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
	}

}

 

180332_cjkP_1243105.png

根据类图结构可以看到

DefaultListableBeanFactory为SimpleAliasRegistry的子类

然后在父类实现了别名的注册,子类直接使用即可。

--分部代码实现
DefaultBeanDefinitionDocumentReader.java类中持有XmlReaderContext readerContext对象
其中this.getReaderContext()其实就是去获取XmlReaderContext
protected final XmlReaderContext getReaderContext() {
	return this.readerContext;
}
当拿到XmlReaderContext对象后,通过XmlReaderContext提供的getRegistry()获取注册器
XmlReaderContext.java类中持有XmlBeanDefinitionReader reader xmlBean读取器,在xmlBean读取器中获取注册器
public final BeanDefinitionRegistry getRegistry() {
	return this.reader.getRegistry();
}
AbstractBeanDefinitionReader.java类中持有
private final BeanDefinitionRegistry registry//BeanDefinitionRegistry为一个接口
public final BeanDefinitionRegistry getRegistry() {
	return this.registry;
}
GenericApplicationContext.java持有DefaultListableBeanFactory beanFactory
public void registerAlias(String beanName, String alias) {
	this.beanFactory.registerAlias(beanName, alias);
}
SimpleAliasRegistry.java
private final Map<String, String> aliasMap = new ConcurrentHashMap(16);
public void registerAlias(String name, String alias) {
	if(alias.equals(name)) {
		this.aliasMap.remove(alias);
	} else {
		String registeredName = (String)this.aliasMap.get(alias);
		if(registeredName != null) {
			if(registeredName.equals(name)) {
				return;
			}

			if(!this.allowAliasOverriding()) {
				throw new IllegalStateException("Cannot register alias \'" + alias + "\' for name \'" + name + "\': It is already registered for name \'" + registeredName + "\'.");
			}
		}

		this.checkForAliasCircle(name, alias);
		this.aliasMap.put(alias, name);
	}

}

总结:其实别名的注册思路很简单。就是在beanFactory容器中去查找当前beanName是否存在别名,如果存在则直接return;如果别名与beanName的名称相同时也return;

这里还加入了一个逻辑就是判断别名是否能够被替换在目前的代码实现直接返回了true,也就是说默认情况可以直接替换别名的。

protected boolean allowAliasOverriding() {
    return true;
}
this.checkForAliasCircle(name, alias)

这里做了一个验证,就是验证当前注册的别名是否被其他的beanName注册过,如果注册过会抛出

throw new IllegalStateException("Cannot register alias \'" + alias + "\' for name \'" + name + "\': Circular reference - \'" + name + "\' is a direct or indirect alias for \'" + alias + "\' already")异常

三、beans处理

beans处理逻辑也比较简单

直接调用了this.doRegisterBeanDefinitions(ele)逻辑,然后我们跟踪代码,发现跟处理rootElement逻辑相同。

protected void doRegisterBeanDefinitions(Element root) {
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
    if(this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute("profile");
        if(StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
            if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if(this.logger.isInfoEnabled()) {
                    this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
                }

                return;
            }
        }
    }

    this.preProcessXml(root);
    this.parseBeanDefinitions(root, this.delegate);
    this.postProcessXml(root);
    this.delegate = parent;
}

四、bean标签处理

TIPS:针对bean标签的处理逻辑相对比较复杂,这里要深入分析。

【接】基于XmlBeanFactory加载bean分析:parseDefaultElement(二)

转载于:https://my.oschina.net/u/1243105/blog/1498953

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值