spring boot 中重复 bean 的本质是多个相同类型 bean 被同时注册,解决核心是让容器只保留一个有效实例并明确指定使用哪一个;常见原因包括扫描范围过宽、手动与自动配置冲突、第三方依赖引入同名 bean 及条件注解失效。

Spring Boot 中出现重复 Bean 实例,本质不是“单例失效”,而是多个相同类型的 Bean 被 Spring 容器同时注册——比如同名类被多处扫描、手动配置与自动装配冲突、或多个 @Configuration 类重复声明了同一个 @Bean。解决核心是:**让容器只保留一个有效实例,并明确指定使用哪一个**。
识别重复 Bean 的来源
常见原因包括:
- 同一类被多个包路径扫描到(如 @ComponentScan 配置过宽,或模块 jar 中已含该类)
- @Configuration 类里用 @Bean 显式创建了与自动扫描类(@Service/@Component)同类型的实例
- 第三方 starter 或依赖引入了同名 Bean(例如两个数据源配置类都定义了 DataSource)
- 条件化配置未生效(@ConditionalOnMissingBean 缺失或判断逻辑有误)
用 @Primary 指定优先使用的 Bean
当多个同类型 Bean 必须共存时,可用 @Primary 标记“首选项”,Spring 在 @Autowired 自动注入时会优先选它:
@Service
public class DefaultUserService implements UserService { ... }
@Service
@Primary // ← 关键标记
public class CachingUserService implements UserService { ... }
注意:@Primary 只影响按类型注入(by-type),不改变 Bean 数量;若需按名称注入,仍要用 @Qualifier("beanName")。
用 @ConditionalOnMissingBean 确保单例唯一性
这是更安全的防御性写法,尤其适合配置类中定义通用 Bean:
@Configuration
public class UserConfig {
@Bean
@ConditionalOnMissingBean(UserService.class)
public UserService userService() {
return new DefaultUserService();
}
}
含义:仅当容器中尚无 UserService 类型的 Bean 时,才创建这个实例。已有则跳过,避免重复。
进阶技巧:可配合 name 属性限定作用域,例如 @ConditionalOnMissingBean(name = "userCacheManager")。
控制扫描范围,从源头避免重复
最彻底的方式是限制组件扫描边界:
- 在主启动类上精确指定 basePackages:
@SpringBootApplication(scanBasePackages = "com.example.app") - 禁用默认扫描,显式导入需要的配置:
@SpringBootApplication(exclude = {AutoConfiguration.class}) - 对第三方模块中的 Bean,用
@EnableAutoConfiguration(exclude = {...})排除不需要的自动配置
如果某模块自带 @Component 类但你不希望它被加载,也可在对应包下添加 META-INF/spring.factories 并移除其自动配置条目。











