Spring源码解析十三

上一篇,我们分析了bean标签下各种子标签的解析,最终都是将这些标签解析到的信息封装到BeanDefinition中。Spring得到这些BeanDefinition之后会做什么呢?肯定是要把这些BeanDefinition信息保存到Spring容器中的。所以Spring拿到这些BeanDefinition之后就要注册到Spring容器的。所以这一篇我们将要介绍BeanDefinition的信息时如何注册的Spring容器的。
我们回顾一下我们上一篇中的内容:
在这里插入图片描述
可以看到,当解析完成各种标签后直接就将BeanDefinition返回了。
我们在回到ParseBeanDefinitionElement的位置看下:
在这里插入图片描述
可以看到,前面解析的bean标签下的各种属性和标签都是在方法ParseBeanDefinitionElement中完成了,然后得到GenericBeanDefinition对象。
在这里插入图片描述
最后,我们可以看到ParseBeanDefinitionElement方法其实就是将BeanDefinition,连带着解析得到的别名aliasesArray一起封装到了BeanDefinitionHolder中,BeanDefinitionHolder我们可以理解为持有BeanDefinition的一个对象而已。

我们在回退到上一个方法的位置看下:
在这里插入图片描述
可以看到,方法parseBeanDefinitonElement返回了我们刚才封装好的BeanDefinitionHolder。
方法 decorateBeanDefinitionIfRequired 其实是对标签进一步的检测,如果发现bean标签中还存在自定义标签,就对自定义标签进行解析,当然自定义标签的解析我们这里不再深究,接下来,我们重点来看下BeanDefinitionReaderUtils中的registerBeanDefinition 方法里面的逻辑,也就是BeanDefinition是如何注册的Spring容器中的。

我们跟进到方法registerBeanDefinition中看下:
在这里插入图片描述
我们就要看到在registerBeanDefinition方法中,首先会从BeanDefinitionholder中获取beanName以及BeanDefinition,然后调用registerBeanDefinition方法进行注册。
我们继续到方法registerBeanDefinition中看下:

@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		// 如果beanDefinition 是AbstractBeanDefinition
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				// 校验beanDefinition 中的methodOverride属性
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
	
		// 判断beanDefinitionMap中是否存在名称为beanName的BeanDefinition  beanDefinitionMap 就是spring容器
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			// 如果配置BeanDefinition 不能被覆盖,此时就会报错
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				// 直接将BeanDefinition放入到beanDefinitionMap中
				this.beanDefinitionMap.put(beanName, beanDefinition);
				// 记录beanName
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		// 如果当前需要注册bean的beanName,已经在spring容器中存在beanDefinition
		// 或者已经根据BeanDefinition 创建出了对应的单例bean对象
		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}

方法中的代码比较多,我们依次来看下,首先,beanDefinition 肯定是AbstractBeanDefinition的实例,所以调用方法validate进行最后一次校验。
我们看下validate方法中如何校验的:
在这里插入图片描述
可以看到,在方法validate中不允许methodOvrrides属性和factoryMethodName属性同时设置,这是为什么呢?不知道大家还记得,在上一篇中解析lookup-method标签和replaced-method标签时,会将这两个标签需要覆盖的方法名设置到MethodOverrides中,一旦MethodOverrides不为空,这就意味着Spring创建出来的bean还要重新覆写这些方法,而factoryMethodName属性也就是工厂方法的名称,了解过工厂设计模式的同学应该都知道,通过工厂方法也可以创建bean,但是这相比于spring默认的创建方式而言,算是一种不允许外界覆盖bean中方法的创建方式了。也就是说要么你通过工厂方法创建Bean,要么就按Spring普通的方式来创建bean。

接下来,方法prepareMethodOverrides就是对MethodOverrides的一些准备工作了:
在这里插入图片描述
我们可以进到这个prepareMethodOverrides方法看下:
在这里插入图片描述
可以看到,在prepareMethodOverrides方法中如果存在MethodOverrides属性的话,就会通过方法prepareMethodOverride依次预处理这些需要覆盖的方法。预处理的方式也比较简单,就是在方法prepareMethodOverride中判断一下,如果lookup-method标签或者replaced-method标签中配置了bean中需要覆盖的方法,就将MethodOverride中的overload属性值设置为false。

接下来,我们继续回到方法registerBeanDefinition中:
在这里插入图片描述
可以看到,beanDefinitionMap根据beanName获取BeanDefinition,我们看下benDefinitionMap是什么:
在这里插入图片描述
可以看到,beanDefinitionMap 就是一个ConcurrentHashMap类型的Map,所以说Spring容器从本质上来说就是一个Map。因为beanDefinitionMap是成员变量,难免会有并发安全的问题,所以这里使用多线程安全的ConcurrentHashMap 作为Spring的容器。
我们继续往后看:
在这里插入图片描述
可以看到,在BeanDefinition 第一次注册时,从beanDefinitionMap中肯定是获取不到任何东西的。而且,BeanDefinition对应的bean还没有创建,第一次直接将beanName 对应的BeanDefinition设置到beanDefinitionMap中,同时将beanName记录到beanDefinitionNames中。
假设刚才注册的bean名称为beanName1,这个时候如果又有一个bean过来注册,并且bean的名称也为beanName1,那会发生什么事情呢?会不会覆盖之前注册的beanNme1对应的value值呢?
我们看下下面的代码:
在这里插入图片描述
可以看到,有一个isAllowBeanDefinitionOverriding 方法约束着,通过方法名称我们可以知道,它是用来判断beanDefinitionMap中的元素是否可以被覆盖的。如果方法isAllowBeanDefinitionOverriding返回结果为true,也就是允许相同名称BeanDefinition 覆盖Spring容器的Map,就会将当前的名称beanName1,以及相应的BeanDefinition设置到beanDefinitionMap中了。
我们看下isAllowBeanDefinitionOverriding 返回的是什么值:
在这里插入图片描述
在这里插入图片描述
allowBeanDefinitionOverriding 默认值是true。也就是在默认的情况下,如果出现相同名称的多个bean来注册,在Spring容器对应的beanDefinitionMap中是允许被覆盖的,所以这个地方也就告诉我们,尽量配置的时候不要出现相同名称的bean,否则会被覆盖的。
我们再来看下,最后的一部分代码:
在这里插入图片描述
可以看到,如果发现当前不是这个名称beanName第一次来注册,或者当前beanName 还没有创建相应的单例时,将会调用方法resetBeanDefinition 重置和beanName相关的缓存。我们在后面分析bean 对象创建的时候,会发现bean对象创建会有各种缓存的。

最后,我们在回到上一个方法中看下:
在这里插入图片描述
这个就是bean 的别名注册了。我们在进到方法registerAlias方法中看下:

@Override
	public void registerAlias(String name, String alias) {
		Assert.hasText(name, "'name' must not be empty");
		Assert.hasText(alias, "'alias' must not be empty");
		synchronized (this.aliasMap) {
			// 如果别名alias和bean的名称相同,就不记录该别名,并且从别名map中删除
			if (alias.equals(name)) {
				this.aliasMap.remove(alias);
				if (logger.isDebugEnabled()) {
					logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
				}
			}
			else {
				String registeredName = this.aliasMap.get(alias);
				if (registeredName != null) {
					// 如果根据别名alias,从aliasMap中获取到的beanName和传入的name相同 就表明当前bean的别名已经注册了,不需要重复注册。
					if (registeredName.equals(name)) {
						// An existing alias - no need to re-register
						return;
					}
					// 如果不允许别名覆盖,就报错
					if (!allowAliasOverriding()) {
						throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
								name + "': It is already registered for name '" + registeredName + "'.");
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
								registeredName + "' with new target name '" + name + "'");
					}
				}
				// 检查别名否存在循环
				checkForAliasCircle(name, alias);
				this.aliasMap.put(alias, name);
				if (logger.isTraceEnabled()) {
					logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
				}
			}
		}
	}

在这里插入图片描述

这个aliasMap 的key 为bean的别名,value 为bean在Spring容器中的实际名称,也就是我们的beanName

1、如果需要注册的别名和bean的名称name相同,这样没必要注册了,并且会从aliasMap中删除该别名
2、如果alias和name不相同,此时就会从aliasMap中,根据alias获取registeredName,如果获取到的registeredName 和当前注册bean的名相同,表明该registeredName 已经是当前注册bean的别名了,不需要重新注册了。
在这里插入图片描述

如果registeredName和当前注册的beanName 不相同,而且alias从aliasMap成功获取了一个registeredName,这就意味着registeredName已经是其他bean的别名了。此时,如果方法allowAliasOverriding 返回false,也就是不允许别名被覆盖。

我们还看到一个checkForAliasCircle方法,我们跟进到方法中看下:
在这里插入图片描述
在这里插入图片描述
它主要是为了检测是否存在别名循环的问题,比如,别alias1对应的bean的名称为name1,但是,如果我们同时还存在别名alias1对应bean的名称为name2,而name2又是bean name1的别名。

最后,我们回到我们最开始分析的地方:
我们分析完了,bean的解析 和 BeanDefinition的注册。现在还有最一个方法。
在这里插入图片描述
最后,当BeanDefinition注册到Spring容器之后会调用fireComponentRegistered方法,发布一个BeanDefinition已经被注册的事件通知而已。

我们补充下我们的流程图:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值