第四篇 再读Spring 之BeanDefinition注册


前言

前面几篇文章中,我们梳理了BeanDefinition相关的Resource、Resource加载、基于XML文件的BeanDefinition不同颗粒度解析,和XML中自定义标签解析。接下来,看看BeanDefinition的注册。

在开始之前,先回顾下BeanDefinition。BeanDefinition是Bean的相关定义。对一个具体的BeanDefinition,对内包含BeanDefinition对应的class,scope,init-method,destory-method等等,对外包含对其他BeanDefinition的关联关系,包括依赖和继承。
到这里,咱们讨论的是单个BeanDefinition。实际工程中,Bean有多个,对应的BeanDefinition也不止一个。于是灵魂拷问来了,要不要管理,如何管理?

所以,本文先YY下BeanDefinition管理的必要性,再看BeanFactory是怎么管理的,最后仔细看下Spring作者在操刀时加入的个人思想。


一、管理的必要性

框架设计

BeanDefinition对象是一类关键对象。主要体现在依赖关系复杂。依赖关系包括非BeanDefinition对BeanDefinition的依赖,以及BeanDefinition之间的依赖,就像中年人上有老,下有小同时还得照顾亲戚。依赖关系复杂,直接体现就是对象构造过程比较曲折,简单说不能 new XXBeanDefinition() 就完事了。

工程实现

由于存在依赖,也需要快速寻找依赖,很自然就想到通过集合集中管理,比如使用Map集合。Spring中也确实是这么干的。于是就需要一个Map集合+写入/获取方法。于是就YY出来了一个BeanDefinitionFactory(实际上是不存在的)接口,提供一个写入和获取方法。具体实现类内部通过Map集合实现读写。

二、Spring的实现

1.抽象接口BeanDefinitionRegistry

Spring首先定义了BeanDefinitionRegistry,提供了读写的方法。这个基本上和我们的想法是

代码如下:

public interface BeanDefinitionRegistry extends AliasRegistry {

	/**
	 * Register a new bean definition with this registry.
	 * Must support RootBeanDefinition and ChildBeanDefinition.
	 * @param beanName the name of the bean instance to register
	 * @param beanDefinition definition of the bean instance to register
	 * @throws BeanDefinitionStoreException if the BeanDefinition is invalid
	 * @throws BeanDefinitionOverrideException if there is already a BeanDefinition
	 * for the specified bean name and we are not allowed to override it
	 * @see GenericBeanDefinition
	 * @see RootBeanDefinition
	 * @see ChildBeanDefinition
	 */
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;

	/**
	 * Remove the BeanDefinition for the given name.
	 * @param beanName the name of the bean instance to register
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 */
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * Return the BeanDefinition for the given bean name.
	 * @param beanName name of the bean to find a definition for
	 * @return the BeanDefinition for the given name (never {@code null})
	 * @throws NoSuchBeanDefinitionException if there is no such bean definition
	 */
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

	/**
	 * Check if this registry contains a bean definition with the given name.
	 * @param beanName the name of the bean to look for
	 * @return if this registry contains a bean definition with the given name
	 */
	boolean containsBeanDefinition(String beanName);

	/**
	 * Return the names of all beans defined in this registry.
	 * @return the names of all beans defined in this registry,
	 * or an empty array if none defined
	 */
	String[] getBeanDefinitionNames();

	/**
	 * Return the number of beans defined in the registry.
	 * @return the number of beans defined in the registry
	 */
	int getBeanDefinitionCount();

	/**
	 * Determine whether the given bean name is already in use within this registry,
	 * i.e. whether there is a local bean or alias registered under this name.
	 * @param beanName the name to check
	 * @return whether the given bean name is already in use
	 */
	boolean isBeanNameInUse(String beanName);

}

2. 具体实现DefaultListableBeanFactory

代码如下(示例):

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

// 省略

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

// 省略
}

到这里,基本上和前面的预期差不多,但是如果仔细看源码,其中的复杂程度远超想象。本文中,我们先关注BeanDefinition注册过程,忽略其他代码。


三、特色方法

removeBeanDefinition

既然都集合管理了,那么增删改查这套应该给整齐了。但具体什么时候会使用删除,后面的文章中我们再讨论。Spring中许多代码在写的时候,方法都是完整的,哪怕暂时用不到可以先留空。至少从逻辑上看,相关操作都是完整的。

BeanDefinitionOverriding

终点关注这个overriding,就意味着可以覆盖。既然可以覆盖总得有一些条件吧。咱们仔细看下源码。

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

		// 省略校验代码 
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
		     // 是否允许覆盖
			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 {
		   // 容器已启动的特殊处理暂时忽略
	    }
	}

从代码中可以看到:

  1. 对于重名的BeanDefinition,如果不允许overriding直接异常;
  2. 如果允许overriding,先比较角色。这个角色在Spring中定义了3种,级别从低到高分别是ROLE_APPLICATION(用户定义Bean), ROLE_SUPPORT(Spring内部使用,可能跟用户有关), ROLE_INFRASTRUCTURE(Spring内部使用,和框架使用者完全无关)。越大优先级越高。高优先级可以覆盖低优先级的BeanDefinition。
  3. 如果允许overriding, 并且两个BeanDefinition不相等直接覆盖;
  4. 关于容器已启动时的特殊处理,后续文章再做讨论。

总结

以上就是今天要讲的内容,本文梳理了Spring中BeanDefinition的注册思路和实现过程。如果对你有所帮助,请让我知道,感谢你的阅读。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值