Spring Boot bean定义名称重复,如何不手动指定@Service名称解决
异常原因
org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'estatRegistreServiceImpl' for bean class [cat.gencat.catsalut.hes.mpi.api.loader.service.EstatRegistreServiceImpl] conflicts with existing, non-compatible bean definition of same name and class [cat.gencat.catsalut.hes.mpi.api.admin.service.impl.EstatRegistreServiceImpl]
该异常是Spring默认的注解Bean命名规则导致:默认将类名首字母小写作为Bean全局名称,你两个不同包下的EstatRegistreServiceImpl类名相同,因此生成的Bean名重复,触发全局唯一性校验失败。
最优解决方案:全局自定义Bean命名生成器(无需修改任何@Service注解)
自定义命名生成器,使用类的全限定名作为Bean名称,全限定名天然全局唯一,从根源避免重名冲突,完全不需要手动维护自定义Bean名字面量。
步骤1:实现自定义命名生成器
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.AnnotationBeanNameGenerator; public class FullQualifiedBeanNameGenerator extends AnnotationBeanNameGenerator { @Override protected String buildDefaultBeanName(BeanDefinition definition) { // 直接返回类的全限定名作为Bean名称 return definition.getBeanClassName(); } }
步骤2:启用命名生成器
Spring Boot项目直接在启动类注解中指定:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(nameGenerator = FullQualifiedBeanNameGenerator.class) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
传统Spring XML配置项目修改组件扫描配置:
<context:component-scan base-package="cat.gencat.catsalut.hes.mpi.api" name-generator="你的包路径.FullQualifiedBeanNameGenerator"/>
说明
- 完全不需要修改现有业务代码中的
@Service、@Component等注解,新增业务类也不需要额外配置,一劳永逸。 - 日常注入使用
@Autowired按类型注入完全不受影响:两个EstatRegistreServiceImpl分别实现不同包下的EstatRegistreService接口,类型天然区分,不需要加@Qualifier。 - 若确实需要按名称注入,填写对应类的全限定名即可:
@Autowired @Qualifier("cat.gencat.catsalut.hes.mpi.api.admin.service.impl.EstatRegistreServiceImpl") private EstatRegistreService adminEstatRegistreService;
可选方案:按模块加前缀的命名生成器
如果觉得全限定名太长,可以自定义生成器根据包路径给不同模块的Bean加统一前缀,比如admin模块的Bean名加admin前缀,loader模块加loader前缀,生成的Bean名为adminEstatRegistreServiceImpl、loaderEstatRegistreServiceImpl,同样不会冲突:
@Override protected String buildDefaultBeanName(BeanDefinition definition) { // 默认首字母小写的类名 String defaultName = super.buildDefaultBeanName(definition); String fullClassName = definition.getBeanClassName(); // 按包路径匹配加前缀 if (fullClassName.contains("admin.service")) { return "admin" + defaultName.substring(0,1).toUpperCase() + defaultName.substring(1); } else if (fullClassName.contains("loader.service")) { return "loader" + defaultName.substring(0,1).toUpperCase() + defaultName.substring(1); } return defaultName; }
配置方式和上述方案一致。
内容的提问来源于stack exchange,提问作者Jordi
相关产品推荐
相关产品推荐

