SpringBoot解决同名类导致的bean名冲突bean name conflicts问题

 更新时间:2023年06月20日 09:37:14   作者:野猿新一  
这篇文章主要介绍了SpringBoot解决同名类导致的bean名冲突bean name conflicts问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

SpringBoot同名类导致的bean名冲突bean name conflicts

问题描述

项目中有两个同名类都叫MyService,只是放在不同的包名下

package com.yeyuanxinyi;
@Service()
public class MyService {
}
package com.yeyuanxiner;
@Service()
public class MyService {
}

当项目启动的时候会报如下错误

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'MyService' for bean class [com.yeyuanxinyi.MyService] conflicts with existing, non-compatible bean definition of same name and class [com.yeyuanxiner.MyService]
    at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:348)
    at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:286)
    at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:132)
    at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:287)
    at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:242)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:199)
    at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:167)
    ... 13 common frames omitted

解决方法

问题分析:

由于以上两个同名类在用@Service注解的时候未指定value值,所以Spring Boot默认会以类名作为bean name,由于两个类名相同导致了bean name相同的冲突

可以通过为同名类指定不同的bean name来解决问题,上面两个同名类修改后如下

再次运行项目就不会报错了

package com.yeyuanxinyi;
@Service("MyService1")
public class MyService {
}
package com.yeyuanxiner;
@Service("MyService2")
public class MyService {
}

同理,以上解决方法也适用于@Component

package com.yeyuanxiner;
@Component("MyComponent1")
public class MyComponent {
}

SpringBoot不同包结构下,同名类冲突导致服务启动失败解决方案

项目背景:

两个项目的包结构和类名都很多相同,于是开始考虑使用加一级包进行隔离,类似于这种结构

但是在启动的过程中,抛出来这样的异常:

Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'nameConflict' for bean class [xom.liuyun.beannameconflict.modelB.NameConflict] conflicts with existing, non-compatible bean definition of same name and class [xom.liuyun.beannameconflict.modelA.NameConflict]

at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:348) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:286) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:132) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:284) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:241) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:198) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:166) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]

... 13 common frames omitted。

原因:

spring提供两种beanName生成策略,基于注解的sprong-boot默认使用的是AnnotationBeanNameGenerator,它生成beanName的策略就是,取当前类名(不是全限定类名)作为beanName。由此,如果出现不同包结构下同样的类名称,肯定会出现冲突。

解决方案如下

1. 自己写一个类实现 org.springframework.beans.factory.support.BeanNameGeneraot接口

public class UniqueNameGenerator extends AnnotationBeanNameGenerator {
     @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        //全限定类名
        String beanName = definition.getBeanClassName();
        return beanName;
    }
}

2. 在启动类上加注解@ComponentScan(nameGenerator = UniqueNameGenerator.class)使刚才我们自定义的BeanName生成策略生效。 

@SpringBootApplication 
@ComponentScan(nameGenerator = UniqueNameGenerator.class)
public class BeanNameConflictApplication {  
    public static void main(String[] args) { 
        SpringApplication.run(BeanNameConflictApplication.class, args); 
    } 
}

这样,问题就可以解决了。

另外解决方式

解决办法:

  • 一:将其中一个实现类改为不同的名字;
  •  二:将其中一个注解变更为一个name为非roleServiceImpl的注解@service(name="aaaa")。

别名:

@Autowired注解时,属性名即为默认的Bean名,如下面的logPrint就是获取beanName=logPrint的bean

@Resource(name=xxx) 直接指定Bean的name,来唯一选择匹配的bean

说明:

@Primary注解

这个注解就是为了解决当有多个bean满足注入条件时,有这个注解的实例被选中

  •  @Resource 指定beanName的是否会被@Primary影响
  • 前面的@Autowired注解 + 属性名的方式,是按照第一节的方式选择呢,还是选择被@Primary标识的实例
  • @Autowired + 随意的一个非beanName的属性,验证是否会选中@Primary标识的注解
  • 根据前面的执行,因此可以知晓,选择bean的方式如下

存在@Primary注解时

  • @Resource注解指定name时,根据name来查找对应的bean
  • @Autowired注解,全部都用@Primary标识的注解
  • @Primary注解要求唯一(非广义的唯一性,并不是指只能用一个@Primary,具体看前面)

不存在@Primary注解时

  • @Resource注解指定name时,根据name来查找对应的bean
  • @Autowired注解时,根据属性名去查对应的Bean,如果查不到则抛异常;如果查到,那即是它了

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java中实现map与对象相互转换的几种实现

    java中实现map与对象相互转换的几种实现

    这篇文章主要介绍了java中实现map与对象相互转换的几种实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • java使用Socket类接收和发送数据

    java使用Socket类接收和发送数据

    Socket类是负责处理客户端通信的Java类。本文主要是介绍java使用Socket类接收和发送数据,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-10-10
  • Java实现定时任务的方法详解

    Java实现定时任务的方法详解

    大家都用过闹钟,闹钟可以说是一种定时任务。那么,在 Java 中,如何实现这样的功能呢?即如何实现定时任务呢?本文就来详细和大家聊聊
    2022-10-10
  • Java如何实现http接口参数和返回值加密

    Java如何实现http接口参数和返回值加密

    这篇文章主要介绍了Java如何实现http接口参数和返回值加密问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • 详解Springboot @Cacheable 注解(指定缓存位置)

    详解Springboot @Cacheable 注解(指定缓存位置)

    这篇文章主要介绍了详解Springboot @Cacheable 注解(指定缓存位置),使用  @Cacheable  注解就可以将运行结果缓存,以后查询相同的数据,直接从缓存中取,不需要调用方法,需要的朋友可以参考下
    2023-09-09
  • IDEA导入Eclipse项目全过程

    IDEA导入Eclipse项目全过程

    这篇文章介绍了如何将Eclipse项目导入到IntelliJ IDEA,并详细步骤如下:新建一个文件夹,用IntelliJ IDEA打开,将项目导入,等待编译完成,配置项目环境和结构,注意文件夹名称可能不同,配置Tomcat,重新编译项目并启动
    2025-11-11
  • Spring事务处理原理步骤详解

    Spring事务处理原理步骤详解

    这篇文章主要介绍了Spring事务处理原理步骤详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java解决Collectors.toMap()空指针报错问题的方法详解

    Java解决Collectors.toMap()空指针报错问题的方法详解

    这篇文章主要为大家详细介绍了Java解决Collectors.toMap()空指针报错问题的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2026-03-03
  • Java中的命名与目录接口JNDI基本操作方法概览

    Java中的命名与目录接口JNDI基本操作方法概览

    这篇文章主要介绍了Java中的命名与目录接口JNDI基本操作方法概览,JNDI提供统一的客户端API使得Java应用程序可以和这些命名服务和目录服务之间进行交互,需要的朋友可以参考下
    2016-03-03
  • java中int转string与string转int的效率对比

    java中int转string与string转int的效率对比

    这篇文章主要介绍了java中int转string与string转int的效率对比,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03

最新评论