You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Bean扩展的正确方式探讨:自定义Starter场景疑问

问题分析与解决方案

你的这种扩展思路是Spring Boot Starter的标准实践之一:Starter提供默认Bean实现,用户通过自定义子类替换默认实现,自动装配时优先使用用户自定义的Bean。但当前出现默认BaseBean被实例化后未销毁的问题,核心原因是条件判断时机不正确,导致Starter的默认Bean在用户自定义Bean注册前就完成了初始化。

为什么会出现双实例?

@ConditionalOnMissingBean(BaseBean.class)的判断逻辑是:在当前配置类处理阶段,若容器中不存在BaseBean类型(包括子类)的Bean定义,则创建默认Bean。如果你的Starter自动配置类加载时机早于用户AppBean的组件扫描,那么在执行getBean()方法时,AppBean还未被注册到容器,条件判断为真,默认BaseBean被实例化;后续AppBean被扫描注册后,由于它是BaseBean的子类,会成为自动装配的优先候选,但已创建的默认BaseBean实例不会被Spring主动销毁,从而出现双实例的情况。

正确的扩展方式调整

要让这种扩展逻辑正常工作,需确保默认Bean仅在用户未提供自定义实现时才被创建,具体步骤如下:

1. 正确配置Starter的自动加载

在Starter的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,添加自动配置类的全类名:

com.example.starter.StarterConfiguration

Spring Boot会保证自动配置类的加载时机晚于用户自定义的@Component扫描,此时AppBean已被注册,@ConditionalOnMissingBean会正确判断,不会创建默认BaseBean。

2. 确保用户自定义Bean被扫描到

确认AppBean所在的包被主启动类的@ComponentScan覆盖(主启动类默认扫描自身包及其子包),若不在默认扫描路径,需手动指定:

@SpringBootApplication(scanBasePackages = {"com.example.app", "com.example.starter"})
public class AppApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppApplication.class, args);
    }
}

3. 优化条件判断的匹配范围

可以显式指定@ConditionalOnMissingBean的搜索策略,确保检查整个容器的Bean定义:

@Configuration
class StarterConfiguration {
    @Bean
    @ConditionalOnMissingBean(value = BaseBean.class, search = SearchStrategy.ALL)
    BaseBean getBean() {
        return new BaseBean();
    }
}

SearchStrategy.ALL是默认值,此配置可增强可读性,明确表示检查所有已注册的Bean。

额外说明

  • 自动装配时优先选择AppBean是正常行为:当容器中存在BaseBean类型的子类Bean时,Spring会优先选择更具体的类型作为自动装配候选;若需更精确控制,可给AppBean添加@Primary注解,明确标记为优先Bean。
  • 若已出现默认Bean未销毁的情况,只能通过调整加载时机避免其被创建,Spring不会主动销毁已初始化的Bean。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 01:10:32