ConflictingBeanDefinitionException:Spring同名bean冲突解决

问题背景

因为项目原因,我所做的项目 A 需要以 maven 依赖的方式依赖项目B进行启动。但当启动时发生了报错,是因为两个项目中存在相同名称的 Bean。
image.png

报错原因

根据 Spring 的 Bean 加载机制,Java Bean 在被实例化之前都会首先被转换成 BeanDefinition 对象,这里面描述了一个bean实例具有的属性值、构造函数参数值以及由具体实现提供的进一步信息。
Spring 需要为 BeanDefinition 中描述的 Bean 对象进行命名和注册,最终形成一个 BeanDefinitionRegistry 注册表。点进它的一个实现类 DefaultListableBeanFactory 的源码可以看到,注册表是一个以 Bean 名字为key,BeanDefinition 为 value 的 Map。
这就解释了,为什么当两个 Bean 的名字重复时,会出现上面的报错了。
image.png

接下来再看,Spring 是如何为一个 Bean 命名的:
通过注解声明的 Bean 的命名主要由 AnnotationBeanNameGenerator 来完成的,源代码如下:
image.png
image.png
通过以上代码可以看到,当使用注解声明一个 Bean ,且没有指定 Bean 的名字的话,会默认使用首字母小写的类名来作为 Bean 的名字。
所以,同名 Bean 冲突报错的出现就是:两个相同类名的类都声明为了 Bean ,且都没有自定义 bean 名称,在项目注册 Bean 的时候,其中一个已经存在了,第二个就不能再存放到 BeanDefinitionRegistry 注册表中了,所以通过报错提醒开发者。

解决措施

最直接的办法当然是修改 Bean 的类名,不让他们重复。但是这样可能涉及的代码改动比较多。那么这时可以从 Bean 的注册上着手。
根据上面的源码,既然是因为 Bean 在往注册表中注册的过程中产生的同名冲突,已知注册表的数据结构是不能改变的,那么我们只能从 Bean 的命名进行着手。
所以我们可以继承和重写 AnnotationBeanNameGenerator 的 generateBeanName 方法,修改 Bean 命名逻辑,再修改项目的 Bean 名称生成器来避免 bean 名称冲突。代码如下:

@Slf4j
@MapperScan("com.xxx.**.mapper")
@SpringBootApplication(scanBasePackages="com.xx.**", nameGenerator = IdpApplicationRunner.SpringBeanNameGenerator.class)
public class IdpApplicationRunner {

    public static class SpringBeanNameGenerator extends AnnotationBeanNameGenerator {
        @Override
        public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
            String shortClassName = super.generateBeanName(definition, registry);

            // 如果存在相同名称的bean,则将要注册的bean的名称设置为全路径名
            if (registry.containsBeanDefinition(shortClassName)) {
                return definition.getBeanClassName();
            }

            return shortClassName;
        }
    }

    public static void main(String[] args) {
        SpringApplication.run(IdpApplicationRunner.class, args);
    }

}
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值