Spring构造器依赖注入如何使用全限定名解决同名Bean冲突
问题根因
这不是Spring设计缺陷,你遇到的是Spring默认Bean命名规则和多模块/代码生成场景不匹配的典型问题,本质是遗漏了对应配置:
Spring默认的AnnotationBeanNameGenerator会取类名首字母小写作为Bean的默认名称,不会拼接包路径,因此不同包下的同名类(你这里是MapStruct生成的Mapper)在被ClassPathBeanDefinitionScanner扫描注册时,会生成完全相同的Bean名,直接在Bean定义注册阶段抛出BeanDefinitionStoreException——这个异常发生在依赖注入之前,和你提到的注入阶段类型校验逻辑没有关系,所以不存在“注入时强制校验全限定名”的配置,问题解决点在Bean注册的命名环节。
解决方案
根据你的项目场景二选一即可:
1. 全局配置全限定类名作为Bean名(推荐多模块项目使用)
Spring官方已经内置了全限定名的Bean命名实现FullyQualifiedAnnotationBeanNameGenerator,不需要自己实现逻辑:
- SpringBoot项目直接在启动类注解上指定命名生成器即可:
@SpringBootApplication(nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- 原生Spring项目在初始化扫描器时手动注入该生成器:
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry); scanner.setBeanNameGenerator(new FullyQualifiedAnnotationBeanNameGenerator());
配置后所有Bean的默认名称会变为类的全限定名(例如com.app.mapper.OrderMapper、com.library.mapper.OrderMapper),从根源上避免同名类冲突。
2. 仅配置MapStruct Mapper的命名规则(不修改全局命名规则时使用)
因为你提到冲突的Bean全部是MapStruct生成的Mapper类,可以只针对MapStruct配置Bean命名策略,不影响其他业务Bean:
在MapStruct的注解处理器配置中(Maven配置在pom.xml的annotationProcessorPaths节点,Gradle配置在annotationProcessor依赖项),添加编译参数:
mapstruct.defaultComponentModel=spring mapstruct.beanNameGenerationStrategy=fullyQualified
配置后MapStruct生成的Mapper类上的@Component注解会自动携带全限定类名作为Bean名,不会和其他模块的同名Mapper产生冲突。
关于Lombok构造注入的补充说明
你使用Lombok @RequiredArgsConstructor 生成构造器的方式本身没有问题,只要你没有修改Spring默认的依赖匹配优先级(先按类型匹配,同类型存在多个候选Bean时再按参数名匹配),使用上述两种方案解决Bean命名冲突后,构造器注入会自动按类型完成匹配,不需要额外调整参数名或添加@Qualifier注解。

内容的提问来源于stack exchange,提问作者JankoHrasko

