转载

Spring源码系列:BeanDefinition载入(下)

在 Spring源码系列:BeanDefinition载入(上) 中已经大概捋了一下解析过程,本篇将记录一下bean的注册过程。

bean的注册就是DefaultListableBeanFactory中registerBeanDefinition方法来完成的。那我就来看registerBeanDefinition这个方法的具体逻辑。

1、beanDefinition类型判断和验证

这里的验证主要是验证不能将静态工厂方法与方法重写相结合(静态工厂方法必须创建实例);

if (beanDefinition instanceof AbstractBeanDefinition) {
	try {
		((AbstractBeanDefinition) beanDefinition).validate();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),
		beanName,"Validation of bean definition failed", ex);
	}
}

2、尝试从beanDefinitionMap中获取老的bean

这里就是先根据beanName从beanDefinitionMap去取BeanDefinition,并将结果给oldBeanDefinition。

BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);

3、beanDefinitionMap中已经存在名为beanName的Beandefinition

如果当前beanDefinitionMap中已经存在名为beanName的Beandefinition了(即检查是否有相同名称的beanDefinition已经在Ioc容器中注册过了)。,如果有,则进行以下具体策略:

  • 如果不允许bean被覆盖,则直接抛出不能重新注册,bean已经存在这样的异常信息
  • 使用框架生成的Bean来代替用户自定义的bean
  • 覆盖原有的Beandefinition
if (oldBeanDefinition != null) {
	if (!isAllowBeanDefinitionOverriding()) {
	    //省略异常代码
	}
	else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
	    //省略异常代码
	}
	else if (!beanDefinition.equals(oldBeanDefinition)) {
		//提示覆盖log信息
	}
	else {
		//提示覆盖log信息
	}
	//覆盖原有的Beandefinition
	this.beanDefinitionMap.put(beanName, beanDefinition);
}

4、beanDefinitionMap不存在名为beanName的Beandefinition

//检查bean的创建阶段是否已经开始,也就是说是否已经创建了
if (hasBeanCreationStarted()) {
    //Cannot modify startup-time collection elements anymore (for stable iteration)
	// 无法修改启动时间收集元素(用于稳定迭代)(译注)
	//注册过程需要保证数据的一致性,所有需要加锁同步
	synchronized (this.beanDefinitionMap) {
	    //注册到beanDefinitionMap中
		this.beanDefinitionMap.put(beanName, beanDefinition);
		//下面就是将当前beanName存放到beanDefinitionNames中
		List<String> updatedDefinitions = new ArrayList<String>(
		this.beanDefinitionNames.size() + 1);
		updatedDefinitions.addAll(this.beanDefinitionNames);
		updatedDefinitions.add(beanName);
		this.beanDefinitionNames = updatedDefinitions;
		//如果单例模式的bean名单中有该bean的name,那么移除掉它。
		//也就是说着,将一个原本是单例模式的bean重新注册成一个普通的bean
		if (this.manualSingletonNames.contains(beanName)) {
			Set<String> updatedSingletons = new
			LinkedHashSet<String>(this.manualSingletonNames);
			updatedSingletons.remove(beanName);
			this.manualSingletonNames = updatedSingletons;
		}
	}
}
// 仍处于启动阶段,bean还没有开始注册
else {
	// Still in startup registration phase
	this.beanDefinitionMap.put(beanName, beanDefinition);
	this.beanDefinitionNames.add(beanName);
	this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;

5、执行缓存清除

  • 1:oldBeanDefinition如果存在,且执行到了这里也没有抛出异常,说明该BeanDefinition已经被覆盖,缓存需要更新。

  • 2:如果是单例模式的bean对象则Set中包含该beanName,执行到这里说明该BeanDefinition已经从一个单例模式的bean变为了一个普通的bean,所以缓存也需要更新。

if (oldBeanDefinition != null || containsSingleton(beanName)) {
	resetBeanDefinition(beanName);
}

OK,我们来看下resetBeanDefinition这个方法:

这个方法的作用就是重置给定bean的所有bean定义缓存,包括从它派生的bean的缓存。

protected void resetBeanDefinition(String beanName) {
	// 如果已经创建,则删除给定bean的合并bean定义。
	clearMergedBeanDefinition(beanName);

	// 如果有的话,从singleton 高速缓存中删除相应的bean。
	//但是这也不是必须的,而只是为了覆盖上下文的默认bean
	//(就是从manualSingletonNames中移除)
	destroySingleton(beanName);
	//递归的方式来 重置具有给定bean作为父项的所有bean定义。
	for (String bdName : this.beanDefinitionNames) {
		if (!beanName.equals(bdName)) {
			BeanDefinition bd = this.beanDefinitionMap.get(bdName);
			if (beanName.equals(bd.getParentName())) {
				resetBeanDefinition(bdName);
			}
		}
	}
}

Bean的注册就到这里了,下一篇学习的是DefaultListableBeanFactory这个集大成者容器。

原文  https://juejin.im/post/5a73c4d3f265da4e7a78266c
正文到此结束
Loading...