Spring配置文件解析之BeanDefinitionDocumentReader详解

 更新时间:2024年02月14日 08:42:20   作者:军伟@  
这篇文章主要介绍了Spring配置文件解析之BeanDefinitionDocumentReader详解,Spring的xml配置文件解析成Document对象,接下来的解析处理工作是在BeanDefinitionDocumentReader中对Document对象进行解析,需要的朋友可以参考下

Spring中的BeanDefinitionDocumentReader

上一篇Spring配置文件解析之BeanDefinitionReader详解中我们已经了解到BeanDefinitionReader已经将Spring的xml配置文件解析成Document对象了,接下来的解析处理工作是在BeanDefinitionDocumentReader中对Document对象进行解析工作了。

BeanDefinitionDocumentReader接口及其实现类:

BeanDefinitionDocumentReader提供的方法:

public interface BeanDefinitionDocumentReader {
 
	void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
			throws BeanDefinitionStoreException;
 
}

在 BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader定义了对一些xml配置文件基本的元素的解析处理操作

在这里我们可能会有一个疑问,在Spring的xml配置文件中经常看到的aop等相关的配置是在什么地方解析处理的,其实他们都是通过NamespaceHandler实现类来完成的,接下来我们会对其进行详细的介绍。

在DefaultBeanDefinitionDocumentReader的registerBeanDefinitions方法中开始对Document进行解析。

	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();
		doRegisterBeanDefinitions(root);
	}

在doRegisterBeanDefinitions中会创建BeanDefinitionParserDelegate来对Document进行解析

protected void doRegisterBeanDefinitions(Element root) {
		
		BeanDefinitionParserDelegate parent = this.delegate;
		//创建BeanDefinitionParserDelegate,真正xml中各种元素的解析
		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;
	}

在parseBeanDefinitions会对Node进行判断,如果是上面配置默认解析的spring标签,则会在DefaultBeanDefinitionDocumentReader中进行解析,否则的话就需要 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)) {
						//默认的一些标签在DefaultBeanDefinitionDocumentReader进行解析
						parseDefaultElement(ele, delegate);
					}
					else {
						//如果不是默认的就需要在通过委派模式来寻找解析处理器
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			//如果不是默认的就需要在通过委派模式来寻找解析处理器
			delegate.parseCustomElement(root);
		}
	}

在parseDefaultElement中会对一些默认的标签import,alias,bean,beans标签进行处理

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);
		}
	}
 

对bean标签解析,最终还是在BeanDefinitionParserDelegate中对元素进行处理解析生成BeanDefinitionHolder,其实bean元素的解析的结果是一个BeanDefinition对象,其包含了所有的bean的属性设置,processBeanDefinition中的BeanDefinitionReaderUtils的处理结果是将BeanDefinition注册到BeanFactory中。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//最终还是在BeanDefinitionParserDelegate中进行元素解析
		//BeanDefinitionHolder是对BeanDefinition的封装,包括BeanDefinition,beanName,aliases
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				//处理的操作是将bean的元数据BeanDifinition注册到BeanFactory中
				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));
		}
	}

总结

BeanDefinitionDocumentReader中也没有对xml中的bean元素进行处理操作,其真正的处理操作是在BeanDefinitionParserDelegate中进行处理的,都是在为他人做嫁衣。

到此这篇关于Spring配置文件解析之BeanDefinitionDocumentReader详解的文章就介绍到这了,更多相关Spring中的BeanDefinitionDocumentReader内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot集成pf4j实现插件开发功能的代码示例

    SpringBoot集成pf4j实现插件开发功能的代码示例

    pf4j是一个插件框架,用于实现插件的动态加载,支持的插件格式(zip、jar),本文给大家介绍了SpringBoot集成pf4j实现插件开发功能的示例,文中通过代码示例给大家讲解的非常详细,需要的朋友可以参考下
    2024-07-07
  • mybatisPlus打印sql配置的四种方法

    mybatisPlus打印sql配置的四种方法

    MyBatis-Plus提供了多种方式来配置SQL打印功能,以便进行调试和性能分析,这篇文章主要介绍了mybatisPlus打印sql配置的四种方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • Java爬虫实现Jsoup利用dom方法遍历Document对象

    Java爬虫实现Jsoup利用dom方法遍历Document对象

    本文主要介绍了Java爬虫实现Jsoup利用dom方法遍历Document对象,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Nacos服务注册客户端服务端原理分析

    Nacos服务注册客户端服务端原理分析

    这篇文章主要为大家介绍了Nacos服务注册客户端服务端原理分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • sonar-scanner连接sonarquebe7的sonar.java.binaries问题的解决方案

    sonar-scanner连接sonarquebe7的sonar.java.binaries问题的解决方案

    今天小编就为大家分享一篇关于sonar-scanner连接sonarquebe7的sonar.java.binaries问题的解决方案,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 基于Nacos实现SpringBoot动态定时任务调度

    基于Nacos实现SpringBoot动态定时任务调度

    本文主要介绍了在Spring Boot项目中使用Spring Scheduling实现定时任务,并通过Nacos动态配置Cron表达式实现任务的动态变更,通过实现SchedulingConfigurer接口和订阅Nacos配置变更事件,成功实现了任务的动态调度和暂停
    2025-11-11
  • JAVA用户自定义事件监听实例代码

    JAVA用户自定义事件监听实例代码

    这篇文章主要介绍了JAVA用户自定义事件监听实例代码的相关资料,需要的朋友可以参考下
    2017-04-04
  • Java zxing生成条形码和二维吗代码实例

    Java zxing生成条形码和二维吗代码实例

    这篇文章主要介绍了java zxing生成条形码和二维吗代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • IDEA2020.2.3

    IDEA2020.2.3 "reading maven projects"卡住的问题

    这篇文章主要介绍了IDEA2020.2.3 "reading maven projects"卡住的问题及问题原因探究,通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-10-10
  • IDEA 插件 mapper和xml互相跳转操作

    IDEA 插件 mapper和xml互相跳转操作

    这篇文章主要介绍了IDEA 插件 mapper和xml互相跳转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02

最新评论