Spring源码学习(五)---BeanDefinitions解析流程

这里主要是使用org.springframework:spring-beans:5.2.0.RELEASE进行分析

一. XmlBeanDefinitionReader

  1. 在上一章Document文件配置读取后,需要注册Bean,当拥有XML文档文件的Document实例对象时,就会被引入XmlBeanDefinitionReader的这个方法。
    在这里插入图片描述1. XmlBeanDefinitionReader里面的 registerBeanDefinitions() 源码
//其中的参数doc是loadDocument加载转换出来的
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	    // 使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		   // 实例化BeanDefinitionReader时候会将BeanDefinitionRegistry传入,默认使用继承自DefaultListableBeanFactory的子类
		int countBefore = getRegistry().getBeanDefinitionCount();
		  // 加载及注册bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// 记录本次加载的BeanDefinition个数
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
  1. 使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
    在这里插入图片描述
  2. 实例化BeanDefinitionReader时候会将BeanDefinitionRegistry传入,默认使用继承自DefaultListableBeanFactory的子类
    在这里插入图片描述
  3. 加载及注册bean

在这里插入图片描述

  1. 记录本次加载的BeanDefinition个数
    在这里插入图片描述
  2. BeanDefinitionDocumentReader是一个接口,而实例化的工作是在createBeanDefinitionDocumentReader()中完成的
  3. 而通过此方法, BeanDefinitionDocumentReader真正的类型其实已经是DefaultBeanDefinitionDocumentReader了

二.DefaultBeanDefinitionDocumentReader

在这里插入图片描述2. DefaultBeanDefinitionDocumentReader里面的 registerBeanDefinitions() 源码

	@Override
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

1. doRegisterBeanDefinitions();

  1. doRegisterBeanDefinitions才是真正地开始进行解析

2. DefaultBeanDefinitionDocumentReader里面的 doRegisterBeanDefinitions 源码

protected void doRegisterBeanDefinitions(Element root) {
		// 专门处理解析
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		if (this.delegate.isDefaultNamespace(root)) {
		// 处理profile属性
			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.isDebugEnabled()) {
						logger.debug("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;
	}
  • 处理流程解析
  1. profile的处理
    在这里插入图片描述

  2. preProcessXml(root)
    在这里插入图片描述

  3. postProcessXml(root)
    在这里插入图片描述
    如果继承自DefaultBeanDefinitionDocumentReader的子类需要在Bean解析前后做一些处理的话,那么只需要重写这两个方法就可以了。

三 . profile属性的使用

  1. 在注册bean的最开始是对PROFILE_ATTRIBUTE属性的解析
    在这里插入图片描述
<?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.xsd">

	//开发环境
    <beans profile="dev">
        ......
    </beans>
    //生产环境
    <beans profile="production">
        ......
    </beans>
</beans>
  1. Web环境中时,在web.xml中配置:
<context-param>
    <param-name>Spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

3.这个特性可以在配置文件中部署两套配置来适用于生产环境和开发环境,这样可以方便的进行切换开发、部署环境,最常用的就是更换不同的数据库。

四. 解析并注册BeanDefinition

  1. 处理了profile后就可以进行XML的读取
  2. parseBeanDefinitions(root, this.delegate)源码在这里插入图片描述

2. DefaultBeanDefinitionDocumentReader里面的 parseBeanDefinitions 源码

	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
	// 对beans的处理
		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)) {
					 // 对bean的处理
						parseDefaultElement(ele, delegate);
					}
					else {
					// 对bean的处理
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}
  1. Spring的XML配置里面有两大类Bean声明

对于根节点或者子节点如果是默认命名空间的话则采用parseDefaultElement方法进行解析,否则使用delegate.parseCustomElement(ele)方法对自定义命名空间进行解析,判断是否默认命名空间还是自定义命名空间的办法是使用node.getNamespaceURI()获取命名空间,并与Spring中固定的命名空间http://www.springframework.org/schema/beans进行比对,如果一致则认为是默认,否则就认为是自定义

//这个是默认的
<bean id="hello" class="com.xizi.pojo.Hello">
</bean>

在这里插入图片描述

//这个是自定义的
<tx:annotation-driven/>

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值