SpringBoot双@EnableJpaRepositories触发BeanDefinitionOverrideException解决咨询
问题复现
参照教程为SpringBoot Repository实现自定义功能,创建新的基础Repository类后将其配置到启动类的@EnableJpaRepositories注解中,启动时报BeanDefinitionOverrideException异常,错误堆栈如下:
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'myRepository' defined in com.my.service.repository.MyRepository defined in @EnableJpaRepositories declared on UpperLevelJpaConfig: Cannot register bean definition [Root bean: class [com.my.data.entity.base.BaseRepositoryFactoryBean]; scope=; abstract=false; lazyInit=true; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in com.my.service.repository.MyRepository defined in @EnableJpaRepositories declared on UpperLevelJpaConfig] for bean 'myRepository': There is already [Root bean: class [com.my.service.repository.BaseRepositoryFactoryBean2]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in com.my.service.repository.MyRepository defined in @EnableJpaRepositories declared on MyServiceApplication] bound.
经排查是项目上层公共配置和服务启动类两处@EnableJpaRepositories配置重复扫描创建Repository实例导致,上层公共配置无法修改,需要可行的绕过方案。
现有相关代码
服务启动类
@SpringBootApplication @RefreshScope @EnableConfigurationProperties @EnableDiscoveryClient @EnableTransactionManagement @EnableJpaRepositories(repositoryFactoryBeanClass = BaseRepositoryFactoryBean2.class) @ComponentScan( basePackages = { "com.my.service", }) public class MyServiceApplication { }
上层公共配置类(无法修改)
@Configuration @EnableConfigurationProperties(value = {PoolDataSourceConfig.class, JpaProperties.class}) @EnableTransactionManagement @EnableJpaRepositories( bootstrapMode = BootstrapMode.LAZY, basePackages = "${jpa.repositoryPackagePath:null}", repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class) public class UpperLevelJpaConfig{ }
可行解决方案
按落地优先级排序提供3种方案:
方案1:调整扫描范围避免重叠
上层配置的扫描路径是${jpa.repositoryPackagePath:null},默认值为null时会扫描配置类所在包及其子包,可做如下调整:
- 把自定义的Repository接口单独放到上层配置不会扫描到的独立包路径下,比如
com.my.service.custom.repository - 修改启动类的
@EnableJpaRepositories注解,显式指定仅扫描自定义Repository路径,同时增加过滤规则排除上层已扫描的公共Repository包:
@EnableJpaRepositories( basePackages = "com.my.service.custom.repository", repositoryFactoryBeanClass = BaseRepositoryFactoryBean2.class, excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.my.common.repository.*") )
同时在项目配置文件中给上层配置的jpa.repositoryPackagePath赋值为公共Repository所在的包,避免上层配置扫描到自定义Repository路径。
方案2:开启Bean定义覆盖兼容
如果不想调整包结构,可以直接在项目配置文件中添加配置允许Bean覆盖,优先级更高的启动类配置会自动覆盖公共配置的Bean定义:
spring: main: allow-bean-definition-overriding: true
该方案改动最小,默认情况下启动类配置优先级高于公共依赖配置,可正常生效。
方案3:自定义后置处理器移除冲突Bean
如果以上两种方案都不适用,可以编写自定义Bean定义注册后置处理器,在Spring注册Bean阶段主动移除上层配置生成的冲突Repository Bean定义:
@Component public class CustomRepositoryBeanPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 移除冲突的Repository Bean定义,保留自己配置的版本 if (registry.containsBeanDefinition("myRepository")) { registry.removeBeanDefinition("myRepository"); } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 无需额外逻辑 } }
内容的提问来源于stack exchange,提问作者chama
相关产品推荐
相关产品推荐

