问题:
项目引用第三方jar包,需要对@Configuration配置类中的某个bean进行覆盖。服务启动过程遇到了bean已被注册异常、新加的bean不加载的问题。
举例:
第三方jar包MybatisPlusConfig 类
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor innerInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //分页 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //乐观锁 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(this.tenantLineHandler())); interceptor.addInnerInterceptor(new SystemLineInnerInterceptor(this.systemLineHandler())); return interceptor; }}
当前项目MybatisPrimaryConfig 类
public class MybatisPrimaryConfig { @Bean public MybatisPlusInterceptor innerInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //分页 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //乐观锁 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); interceptor.addInnerInterceptor(new SystemLineInnerInterceptor(this.systemLineHandler())); return interceptor; }}
1.思路是MybatisPrimaryConfig类的方法bean名字innerInterceptor覆盖MybatisPlusConfig类的方法bean名字innerInterceptor
2.步骤是在springboot中,allowBeanDefinitionOverriding 默认为false;spring默认为true。需要在application.properties中新增spring.main.allow-bean-definition-overriding=true。
3. bean加载顺序
配置allowBeanDefinitionOverriding为true后,却出现新配置不注册的问题。@SpringBootApplication的属性scanBasePackages数组,注册bean时,是按数组顺序注册的。把引用包的包名写在项目包名前面,项目中的配置类才可覆盖掉引用包的bean。@SpringBootApplication(scanBasePackages={"com.qm.qfc.common.entity.config","com.qm.qfc.dpf.dpfservice"})
- 1.spring中的org.springframework.context.annotation.ComponentScanAnnotationParser包扫描代码
-
- public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
- ....
- Set<String> basePackages = new LinkedHashSet();
- String[] basePackagesArray = componentScan.getStringArray("basePackages");
- String[] var19 = basePackagesArray;
- int var21 = basePackagesArray.length;
-
- int var22;
- for(var22 = 0; var22 < var21; ++var22) {
- String pkg = var19[var22];
- String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ",; \t\n");
- Collections.addAll(basePackages, tokenized);
- }
-
- Class[] var20 = componentScan.getClassArray("basePackageClasses");
- var21 = var20.length;
-
- for(var22 = 0; var22 < var21; ++var22) {
- Class<?> clazz = var20[var22];
- basePackages.add(ClassUtils.getPackageName(clazz));
- }
-
- if (basePackages.isEmpty()) {
- basePackages.add(ClassUtils.getPackageName(declaringClass));
- }
-
- scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
- protected boolean matchClassName(String className) {
- return declaringClass.equals(className);
- }
- });
- return scanner.doScan(StringUtils.toStringArray(basePackages));
- }
-
- 2.在方法1中查看doScan方法是在org.springframework.context.annotation.ClassPathBeanDefinitionScanner类
-
- 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;
- }