springboot bean覆蓋注冊的問題-allowBeanDefinitionOverriding配置
問題描述
問題分析
1. allowBeanDefinitionOverriding配置
2. bean加載順序
問題描述
項目引用三方jar包,需要對@Configuration配置類中的某個bean進行重寫。過程中遇到了bean已被注冊異常、以及新加的bean不加載的問題。
問題分析
測試項目中的問題時,寫了兩個config,都注冊了RestTemplate
DefaultConfig
package top.macondo; @Configuration public class DefaultConfig { @Bean public RestTemplate getRestTemplate() { System.out.println("default bean"); return new RestTemplate(); } }
NewConfig
package com.example; @Configuration public class NewConfig { @Bean public RestTemplate getRestTemplate(){ System.out.println("new bean"); return new RestTemplate(); } }
1. allowBeanDefinitionOverriding配置
在默認情況下,啟動服務后,會報bean已被注冊異常。
The bean 'getRestTemplate', defined in class path resource [top/macondo/DefaultConfig.class], could not be registered. A bean with that name has already been defined in class path resource [com/example/NewConfig.class] and overriding is disabled.
springboot中,allowBeanDefinitionOverriding 默認為false;spring默認為true。需要在application.properties中新增spring.main.allow-bean-definition-overriding=true
參考spring中 allowBeanDefinitionOverriding(spring.main.allow-bean-definition-overriding) 分析
2. bean加載順序
配置allowBeanDefinitionOverriding為true后,卻出現新配置不注冊的問題。經過對加載流程的進一步排查,發現NewConfig中的RestTemplate被DefaultConfig覆蓋。
@SpringBootApplication的屬性scanBasePackages數組,注冊bean時,是按數組順序注冊的。把引用包的包名寫在項目包名前面,項目中的配置類才可覆蓋掉引用包的bean。
@SpringBootApplication(scanBasePackages = {"top.macondo","com.example"}) spring中的ComponentScanAnnotationParser包掃描代碼 protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); //依次對basePackages中配置的類進行注入 for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); ... } return beanDefinitions; }