一、类职责
解析dom中的import、alias元素,并委派(BeanDefinitionParserDelegate)处理beans、bean元素
二、主流程
———————————————————————————————-
DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
1.获取文档根元素 //Element root = doc.getDocumentElement();
2.创建BeanDefinitionParserDelegate ,该类具体处理文档中的
3.排除掉Environment中不被接受地profile
4.文档处理前的 前置处理(空实现,方便扩展)//preProcessXml()
5.利用BeanDefinitionParserDelegate将文档解析为beanDefinition(下面进行具体分析) //parseBeanDefinitions
6.文档的后置处理(空实现,方便扩展)//postProcessXml();
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
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)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
———————————————————————————————–
DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
1.dom根元素是否存在于默认的命名空间中
1.1 在命名空间中 执行后续步骤
1.2 不在命名空间中,执行BeanDefinitionParserDelegate的定制处理(BeanDefinitionParserDelegate)
2.子元素是否存在于默认命名空间
2.1 在命名空间中,执行parseDefaultElement(ele, delegate)//下面分析;
2.2 不在命名空间中,执行BeanDefinitionParserDelegate的定制处理(BeanDefinitionParserDelegate)
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);
}
}
———————————————————————————————————————–
DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
分别对import、beans、alias、bean元素做处理
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
下面我们着重分析processBeanDefinition的过程
三、processBeanDefinition代码分析
1.把xml文档中的bean标签解析成BeanDefinitionHolder
实现由:BeanDefinitionParserDelegate.parseBeanDefinitionElement
2.对生成的BeanDefinitionHolder再次处理(针对以下两种情况)
2.1(attr属性空间与bean空间不一致)
<!--外部命名空间为bean 内部却为p-->
<bean id="viewResolver" p:prefix="/WEB-INF/view/" p:suffix=".jsp"/>
2.2(子标签内外空间不一致)
<bean>
<!-- 外部为bean空间,内部为task空间-->
<task:scheduler id=""/>
</bean>
调用BeanDefinitionParserDelegate.decorateIfRequired修饰处理
3.以beanName为K,以beanDefinition为V 存入beanFactory.beanDefinition
以beanName为K,以alias为V 存入beanFactory.alias
4.触发组件注册事件(空实现)
四、补充
1.对import标签的解析
如下:
<import resource="com/test/dao/dao-${test}.xml" />
源码如下:
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
// Resolve system properties: e.g. "${user.dir}"
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
}
分析:
1.先读取到import标签中的resource属性
2.使用Environment去替换${}代表的值
注:Environment中存储了系统属性(System.getProperty)和环境变量(System.getenv)