《Spring源码深度解析》阅读笔记5-默认标签的解析之bean标签的解析及注册

默认标签的解析是在parseDefaultElement函数中进行的,函数中的功能逻辑一目了然,分别对4中不同的标签(import、alias、bean和beans)做了不同的处理。
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);
		}
	}

bean标签的解析及注册
在4中标签的解析中对bean标签的解析最为复杂也最为重要,所以我们从此标签开始深入解析。首先我们进入函数processBeanDefinition(ele, delegate)。
/**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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));
		}
	}
代码的大致逻辑如下:
(1)首先委托BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类型的实例bdHolder。经过这个方法后,bdHolder实例已经包含我们配置文件的各种属性了,例如class、name、id、alias之类的属性;
(2)当返回的bdHolder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析;
(3)解析完成后,需要对解析后的bdHolder进行注册,同样,注册操作委托给了BeanDefinitionReaderUtils类的registerBeanDefinition方法;
(4)最后发出响应事件,通知相关的监听器,这个Bean已经加载完成了。

1、解析beanDefinition
下面我们就针对各个操作做据日分析。首先我们从元素解析及信息提取开始,也就是BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele),进入BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法。
parseBeanDefinitionElement方法完成的主要工作包含一下内容:
(1)提取元素的id以及name属性;
(2)进一步解析标签其他属性并统一封装至GenericBeanDefinition类型的实例中;
(3)如果检测到bean没有指定beanName,那么使用默认规则为此Bean生成beanName;
(4)将获取到的信息封装到BeanDefinitionHolder。
2、AbstractBeanDefinition属性
当完成了对XML文档到GenericBeanDefinition的转换后,XML中所有的配置都可以在GenericBeanDefinition的实例类中找到对应的配置。
但是GenericBeanDefinition只是子类实现,大部分的通用属性其实都保存在了AbstracBeanDefinition中。
3、解析默认标签中的自定义标签元素
接下来进行bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder)代码的分析,首先大致了解下这句代码的作用,其实我们可以从语义上分析:如果需要的话就对beanDefinition进行装饰,那这句代码到底有什么作用呢?
其实这句代码使用于这样的场景,如:
<bean id="test" class=""test.MyClass"><mybean:user username="aaa"/></bean>
当Spring中的bean使用的是默认的标签配置,但是其中的子元素却使用了自定义的配置时,这句代码便会起作用了。在decorateBeanDefinitionIfRequired方法中对于程序默认的标签的处理其实是直接略过的,因为默认的标签到这里已经被处理完了,这里只对bean的自定义属性感兴趣。在方法中实现了寻找自定义属性并根据自定义属性寻找命名空间处理器,并进行进一步的解析。
4、注册解析的BeanDefinition
至此配置文件的解析也解析完了、装饰也装饰完了,对于得到的beanDefinition已经可以满足后续的使用要求了,唯一还剩下的工作就是注册了,也就是函数中BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())代码的解析了。
在registerBeanDefinition方法中,解析的beanDefinition都会被注册到BeanDefinitionRegistry类型的实例registry中,而对于beanDefinition的注册分成了两部分:通过beanName的注册以及通过别名的注册。
(1)通过beanName注册BeanDefinition
对于beanDefiniton的注册,或许很多人认为的方式就是将beanDefinition直接放入map中就好了,使用beanName作为key。确实Spring就是这么做的,只不过除此之外,它还做了点别的事情。
  • 对于AbsractBeanDefinition的校验。在解析XML文件的时候我们提过检验,但是此校验非彼校验,之前的校验是针对XML格式的校验,而此时的校验是针对AbsractBeanDefinition的methodOverrides属性的;
  • 对beanName已经注册过的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖;
  • 加入map缓存;
  • 清楚解析之前留下的对应的beanName的缓存。
(2)注册别名alias的步骤如下:
  • alias与beanName相同情况处理。若alias与beanName名称相同则不需要处理并删除原有alias;
  • alias覆盖处理。若aliasName已经使用并已经指向了另一个beanName则需要根据用户的设置进行处理;
  • alias循环检查。当A->B存在时,若再次出现A->C->B的时候则会抛出异常;
  • 注册alias。

5、通知监视器解析及注册完成
通过代码getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))完成此工作,这里的实现只为扩展,当程序开发人员需要对注册BeanDefinition事件进行监听时可以通过注册监听器的方式并将处理逻辑写入监听器中,目前的Spring中并没有对此事做任何的逻辑处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值