SpringBoot 基础概念:注册BeanDefinition
- 1. 前言
- 2. BeanDefinitionReaderUtils#registerBeanDefinition
- 3. DefaultListableBeanFactory#registerBeanDefinition
1. 前言
问题:为什么需要注册BeanDefinition?
为了后续实例化。Spring架构是将Bean的定义信息注册流程和Bean的实例化过程分开的。
BeanDefinition就是对Bean的定义的信息,包含了class等信息。
2. BeanDefinitionReaderUtils#registerBeanDefinition
/*** Register the given bean definition with the given bean factory.* @param definitionHolder the bean definition including name and aliases* @param registry the bean factory to register with* @throws BeanDefinitionStoreException if registration failed*/
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// Register bean definition under primary name.String beanName = definitionHolder.getBeanName();registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// Register aliases for bean name, if any.String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}
}
- 该方法是注册BeanDefinition的工具方法。
- 参数:
definitionHolder:是对BeanDefinition的封装,里面有beanName和aliases(bean的别名)。
BeanDefinitiion:Bean的一些定义信息,包含class信息。
registry:可以理解为DefaultListableBeanFactory。 - 将BeanDefinition注册到DefaultListableBeanFactory。将别名与beanName进行绑定,方便通过别名获取bean,别名与bean的名称是不能相互依赖的。
3. 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) {//如果已经注册了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_INFRASTRUCTUREif (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 + "]");}}//注册BeanDefinitionthis.beanDefinitionMap.put(beanName, beanDefinition);}else {//没有注册相同的BeanDefinitionif (hasBeanCreationStarted()) {//已经开始了实例化Bean// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {//使用了copyOnWrite原理,读写分离地去注册BeanDefinitionthis.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的阶段,那么就直接去注册BeanDefinitionthis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);//移除了手动注册的单例名称removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}//如果单例池中已经注册了相同的实例,那么就重置BeanDefinitionif (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);}
}
- 如果已经注册了BeanDefinition,那么就判断是否循序覆盖,不允许覆盖则抛出异常。是否允许覆盖是在spring.main.allow-bean-definition-overriding配置,在SpringBoot启动流程中有讲解。
SpringBoot 源码解析2:启动流程 - 如果已经该是实例化Bean的流程,那么就使用copyOnWrite原理注册BeanDefinition和beanName。因为Bean的实例化流程可能是用户多线程去getBean的,就会引发线程安全问题。
- 如果没有开始实例化流程,那么就直接注册BeanDefinition和BeanName。
- 移除了手动注册的beanName,Spring原则是优先使用用户配置,再使用内部默认配置。
- 如果单例池中已经注册了相同的实例,那么就重置BeanDefinition,即删除单例池中的对象,重新注册BeanDefinition,后续重新去实例化。