今天看啥  ›  专栏  ›  JayminAuthor

[Spring]BeanDefinitionRegistry-BeanDefinition注册

JayminAuthor  · 掘金  ·  · 2021-02-08 17:09
阅读 29

[Spring]BeanDefinitionRegistry-BeanDefinition注册

BeanDefinitionRegistry

Spring中BeanDefinition的注册接口,常见的实现有DefaultListableBeanFactoryGenericApplicationContext。看看它的接口清单:

public interface BeanDefinitionRegistry extends AliasRegistry {
    // 往注册表中注册一个BeanDefinition实例
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;
	// 从注册表中移除带有该BeanName的BeanDefinition
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	// 通过beanName从注册表中获取BeanDefinition
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
	// 判断当前是否已经注册了该beanName的BeanDefinition
	boolean containsBeanDefinition(String beanName);
	// 获取当前注册的所有BeanDefinition的Name
	String[] getBeanDefinitionNames();
	// 获取当前已注册的BeanDefinition数量
	int getBeanDefinitionCount();
	// beanName(标识)是否被占用
	boolean isBeanNameInUse(String beanName);
}
复制代码

UML

UML

  • SimpleBeanDefinitionRegistry:BeanDefinitionRegistry较为简单的实现,仅提供注册能力,不提供工厂级别的能力,可作为简单的例子提供给读者做test使用.
  • DefaultListableBeanFactory:Spring最早可以独立运行的工厂类,不仅有容器注册功能,还是一个功能健全的Bean工厂。
  • GenericApplicationContext:Spring通用上下文,需要较多的自定义实现。

DefaultListableBeanFactory的注册功能

前程回顾

上文中提到,BeanDefinitionReader在调用完BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);后,会调用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());方法对该BeanDefinition进行注册.

DefaultListableBeanFactory会将注册后的BeanDefinition放到一个ConcurrentHashMap的Map中进行存储,Key为beanName,Value为BeanDefinition。

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
复制代码

注册的入口

这里传入了两个参数,bdHolder为BeanDefinition的包装器,getReaderContext().getRegistry()为DefaultListableBeanFactory。为什么是DefaultListableBeanFactory?因为Spring在实例化XmlBeanDefinitionReader的时候将容器本身作为参数进行了传递,这在设计模式上也可以称为委托。

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
复制代码

DefaultListableBeanFactory的多职能

DefaultListableBeanFactory本身不仅作为工厂使用,而且还可以用作注册器,资源加载器。

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 这里就是委托的体现,将DefaultListableBeanFactory作为构造参数传入了XmlBeanDefinitionReader中
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}
复制代码

进入到构造函数中,发现DefaultListableBeanFactory在这里已经充当了registry的职能了.

	public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
		super(registry);
	}
复制代码

注册器实例

注册BeanDefinition-注册name和aliases

	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		// 向容器注入BeanDefinition的名称和BeanDefinition本身
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		// 如果该BeanDefinition存在别名,再对别名进行注册
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}
复制代码

DefaultListableBeanFactory#registerBeanDefinition

注意,这里已经到达了DefaultLististableBeanFactory的registerBeanDefinition中了,上面的registry指向的是DefaultLististableBeanFactory.这里梳理一下主要的逻辑

    1. 判断是否为AbstractBeanDefinition的实例,如果是,校验该BeanDefinition是否有声明需要overrides的方法,如果有,创建代理类进行代理。
    1. beanDefinitionMap中尝试获取该beanName的BeanDefinition.
    1. 如果beanDefinitionMap已经有了,检测是否允许BeanDefinition覆盖。如果允许,则用put进行更新操作.
    1. 如果从beanDefinitionMap获取不到,证明是新的BeanDefinition,查看工厂的bean是否进入已创建的阶段了,如果是,则证明是动态注册bean的方式.使用synchronizedbeanDefinitionMap上锁,让进行put操作,再依次更新beanDefinitionNames和从manualSingletonNames(手动注册单例的名称列表,按注册顺序。)中将该beanName移除
    1. 如果该BeanDefinition已存在,并且在单例缓存中,那么进行resetBeanDefinition,这是一个递归的过程,主要的工作是:清除合并的BeanDefinition缓存,从单例缓存中将该BeanName移除,通知处理器进行reset操作.
	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 {
				// 校验look up 和 replace method 是否存在并且参数合法,如果存在,对该BeanDefinition进一步处理
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}
		// 从注册表中获取该BeanDefinition实例
		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 + "]");
				}
			}
			// 将beanName作为key,BeanDefinition作为value,放到容器map中
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			// 是否开始创建bean实例,如果已经有该实例,那么本次为动态的形式
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				// 锁住注册表
				synchronized (this.beanDefinitionMap) {
					// 更新beanDefinition
					this.beanDefinitionMap.put(beanName, beanDefinition);
					// 创建一个长度为beanDefinitionNames+1的列表
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					// 先将存量的beanDefinitionName存储
					updatedDefinitions.addAll(this.beanDefinitionNames);
					// 再存储增量的beanName,顺序存储
					updatedDefinitions.add(beanName);
					// 更新整个BeanDefinitionNames
					this.beanDefinitionNames = updatedDefinitions;
					// 从单例BeanName列表中移除该beanName,如果this.manualSingletonNames中contains该beanName,执行remove操作
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				// 启动阶段
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			// 将注册期间冻结的beanName列表清除,一个volatile修饰的String数组,Spring内存优化操作
			this.frozenBeanDefinitionNames = null;
		}
		// 检测是否存在该BeanDefinition且存在于IOC中
		if (existingDefinition != null || containsSingleton(beanName)) {
			// 重置注册的BeanDefinition缓存
			// 包括BeanDefinition的父类以及合并的BeanDefinition缓存,即mergeBeanDefinition
			// Spring会把有parent属性的Bean属性进行合并
			resetBeanDefinition(beanName);
		}
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}
复制代码

DefaultListableBeanFactory#resetBeanDefinition

	protected void resetBeanDefinition(String beanName) {
		// Remove the merged bean definition for the given bean, if already created.
		// 如果该beanName发生过merge操作,remove已经合并出的beanDefinition
		clearMergedBeanDefinition(beanName);

		// Remove corresponding bean from singleton cache, if any. Shouldn't usually
		// be necessary, rather just meant for overriding a context's default beans
		// (e.g. the default StaticMessageSource in a StaticApplicationContext).
		// 从单例缓存中remove该beanName
		destroySingleton(beanName);

		// Notify all post-processors that the specified bean definition has been reset.
		// 通知MergedBeanDefinitionPostProcessor,这个特殊的beanDefinition已经进行了重置
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			if (processor instanceof MergedBeanDefinitionPostProcessor) {
				((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
			}
		}

		// Reset all bean definitions that have the given bean as parent (recursively).
		// 找出容器中与当前beanName不相同的bd,查看paretName是否跟当前beanName相同。
		// 即父bean被清除了,子bean也应该要重置
		for (String bdName : this.beanDefinitionNames) {
			if (!beanName.equals(bdName)) {
				BeanDefinition bd = this.beanDefinitionMap.get(bdName);
				// Ensure bd is non-null due to potential concurrent modification
				// of the beanDefinitionMap.
				if (bd != null && beanName.equals(bd.getParentName())) {
					// 递归调用,如果该bean还有子bean,继续进行清除
					resetBeanDefinition(bdName);
				}
			}
		}
	}
复制代码

流程图

Registry

总结

  • BeanDefinition的注册具体表现为往DefaultListableBeanFactory中的beanDefinitionMap中添加一个BeanDefinition.
  • BeanDefinitionReader将注册功能委托给了DefaultListableBeanFactory进行注册.该注册器在初始化的时候进行了构造注入.
  • 在注册期间,Spring会校验是否允许BeanDefinition覆盖.
  • Spring支持在工厂创建Bean实例后进行动态注册BeanDefinition.



原文地址:访问原文地址
快照地址: 访问文章快照