0103BeanDefinition注册-Bean生命周期-spring

1 BeanDefinitionRegistry

在之前的解析对象新建的时候,都需要接收一个BeanDefinitionRegistry类型的对象。BeanDefinitionRegistry是BeanDefinition注册的接口,提供注册需要的一些方法。实现了AliasRegistry别名注册接口。源码如下:

package org.springframework.beans.factory.support;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.AliasRegistry;


public interface BeanDefinitionRegistry extends AliasRegistry {

   /**
    * 注册BeanDefinition
    * @param beanName 
    * @param beanDefinition 
    * @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;

   /**
    * 根据beanName移除BeanDefinition
    * @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;

   /**
    * 根据beanName获取BeanDefinition
    * @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;

   /**
    * 根据beanName检查是否包含BeanDefinition
    * @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);

}

那么BeanDefinitionRegistry的具体实现类是哪个呢?和我们之前追踪bean解析一样,参考上一篇0102Bean配置和解析-Bean生命周期-spring,我们可以追踪下BeanDefinition完成解析后,注册过程,看看使用了哪个实现类。

以AnnotatedBeanDefinitionReader解析注册为例,方法doRegisterBean()

	private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {
		// 解析bean元信息为BeanDefinition对象
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		// 省略

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		// BeanDefinition注册
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

继续调用BeanDefinitionReaderUtils.registerBeanDefinition()方法,

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

   // 注册
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // 注册别名
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

继续调用BeanDefinitionRegistry对象的registerBeanDefinition()方法,在BeanDefinitionRegistry的几个实现类中 ,SimpleBeanDefinitionRegistry只用于简单测试,GenericApplicationContext实际内部维护DefaultListableBeanFactory对象

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

	private final DefaultListableBeanFactory beanFactory;
	// 省略
}

即我们可以认为DefaultListableBeanFactory是目前BeanDefinitionRegistry的唯一(?)实现类。

2 DefaultListableBeanFactory

想知道DefaultListableBeanFactory注册BeanDefinition都做了什么,这里我们了解下DefaultListableBeanFactor和BeanDefinition注册相关的部分内部相关结构。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
      implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
  
   /** 是否允许覆盖 */
   private boolean allowBeanDefinitionOverriding = true;

   
   /** beanName-BeanDefinition 键值对的map */
   private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

   
   /** beanName List集合 */
   private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

   /** 手动注册单例beanName Set集合 */
   private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

    // 省略
}
  • DefaultListableBeanFactory同时(间接)实现了BeanFactory和BeanDefinitionRegistry接口。

3 BeanDefinitionRegistry注册BeanDefinition都做了什么

上面追踪过程中,BeanDefinitionReaderUtils.registerBeanDefinition()方法第一部分完成BeanDefinition的注册,第二部分完成别名注册。

3.1 注册BeanDefinition

核心过程调用DefaultListableBeanFactory的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");

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

   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   if (existingDefinition != null) {
      // 省略
       // beanDefinitionMap已经存在同名beanName BeanDefinition定义,覆盖
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      if (hasBeanCreationStarted()) {
         // 如果Bean已经开始创建,为了迭代稳定,不能修改用于创建Bean的集合
         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
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         removeManualSingletonName(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (existingDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
   else if (isConfigurationFrozen()) {
      clearByTypeCache();
   }
}

主要执行流程:

  • beanDefinitionMap根据beanName获取BeanDefinition对象existingDefinition

  • 如果existingDefinition不为空,说明已经注册过

    • 执行覆盖操作,不详述
  • 否则是首次注册

    • 判断hasBeanCreationStarted(),即是否已经开始创建Bean

      • 如果已经开始创建Bean,那么相关的集合不能修改
      • 执行最终3步
    • 否则

      • 执行最终3步

    注册BeanDefinition最终的3步就是:

  • 把beanName-BeanDefinition键值对放入beanDefinitionMap

  • 把beanName放入beanDefinitionNames

  • removeManualSingletonName中移除beanName,如果有的话

3.2 注册别名

别名注册最后会调用SimpleAliasRegistry类的registerAlias方法

	private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);


	@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) {
			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) {
					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 + "'");
				}
			}
		}
	}

把name-alias键值对放入map。

BeanDefinitionRegistry注册BeanDefinition,最终就是把相关信息放入各自集合中,并不会创建Bean。

后记

❓QQ:806797785

⭐️源代码仓库地址:https://gitee.com/gaogzhen/spring6-study

参考:

[1]Spring系列之Bean生命周期详解[CP/OL].

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

gaog2zh

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

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

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

打赏作者

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

抵扣说明:

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

余额充值