springboot1.X 和2.X 关于Bean名字相同时覆盖问题

在2版本之前的版本,项目中有两个相同名字的bean是可以启动成功的,但是会有覆盖问题

但是在2.X版本的时候会报错:

could not be registered. A bean with that name has already been defined in class path resource

这时候解决办法可以在配置文件中添加:

spring.main.allow-bean-definition-overriding=true

/** 是否允许使用相同名称重新注册不同的bean实现. 默认是允许*/
private boolean allowBeanDefinitionOverriding = true;

/**
 * Set whether it should be allowed to override bean definitions by registering
 * a different definition with the same name, automatically replacing the former.
 * If not, an exception will be thrown. This also applies to overriding aliases.
 * 

Default is "true".【这里明确说明了默认是true】 * @see #registerBeanDefinition */ public boolean isAllowBeanDefinitionOverriding() { return this.allowBeanDefinitionOverriding; } @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); } } //bean加载到spring的工程中后,会存储在beanDefinitionMap中,key是bean的名称。 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) {//不为空,说明相同名称的bean已经存在了 if (!isAllowBeanDefinitionOverriding()) {//如果不允许相同名称的bean存在,则直接抛出异常 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 + "]"); } } //可见,上面allowBeanDefinitionOverriding =true时,只是记录了一些日志,然后后来发现的这个bean,会覆盖之前老的bean。 this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }

 

上面贴出来的是spring的代码,而springboot2.X对这个参数又进行了二次封装,springboot中的allowBeanDefinitionOverriding是没有初始化默认值的,我们知道,java中的boolean类型不初始化时是false。
springboot中源代码:

在SpringApplication类中
public class SpringApplication {
    ...
//boolean没初始化,所以默认为false
private boolean allowBeanDefinitionOverriding;
...

 private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        this.postProcessApplicationContext(context);
        this.applyInitializers(context);
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            this.logStartupInfo(context.getParent() == null);
            this.logStartupProfileInfo(context);
        }

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
       //将false值传过去
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }

        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }

        Set sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        this.load(context, sources.toArray(new Object[0]));
        listeners.contextLoaded(context);
    }

 
  

而在1.5.8版本中,SpringApplication中,没有allowBeanDefinitionOverriding属性,因此在prepareContext方法中也就没有对allowBeanDefinitionOverriding进行赋值为false,所以在springboot1.5.8版本中默认就是支持名称相同的bean的覆盖

你可能感兴趣的:(Spring)