Skip to content

Spring Bean 注册到容器有哪些方式? ​

  • 标签:后端、Spring

🏛 业务架构师 ​

Spring Bean 注册到容器的方式,按"声明主体"分四类:

  1. 注解声明 + 组件扫描:@Component/@Service/@Repository/@Controller 标注类,@ComponentScan 指定包路径扫描。业务代码的主力方式;
  2. @Bean 方法:配置类中显式定义,适合第三方 SDK 对象(你没有源码加不了注解)和需要自定义构造逻辑的场景;
  3. @Import 导入:直接导入配置类、普通类,或实现 ImportSelector/ImportBeanDefinitionRegistrar 编程式批量注册——Spring Boot 自动配置的底层机制(@EnableAutoConfiguration 通过 Registrar 加载 AutoConfiguration.imports 清单);
  4. FactoryBean 间接产出:注册的是工厂,容器管理它生产的产品(MyBatis Mapper、Feign 客户端)。

此外还有 BeanDefinitionRegistryPostProcessor 在容器启动早期编程式注册,以及 XML <bean> 声明(遗留系统维护用)。

架构师视角,我关注的是注册方式背后的治理逻辑:

  • 业务组件一律注解声明——IDE 可检索、review 直观;
  • 基础设施能力封装成 starter,用 @Import + 条件装配对外供给——业务方引依赖即用,组件升级不侵入业务仓库;
  • 团队自己写公司级 starter 时,必须配好 AutoConfiguration.imports 和 @ConditionalOnClass,让能力"该启用时才启用"。

一句话:注册方式的选择体现"业务代码"与"平台能力"的边界——业务用声明式,平台用编程式,边界清晰双方都轻。

🏗 系统架构师 ​

五条路径,按使用层次分:

  • 注解扫描:@Component 系类级注解加 @ComponentScan——自有业务代码默认方式;
  • @Bean 方法:Java Config 显式声明,解决第三方类无法加注解的装配(连接池、Redis 客户端);
  • @Import 三态:导入配置类、ImportSelector(批量返回类名)、ImportBeanDefinitionRegistrar(直接操作 BeanDefinition)——自动配置的骨架:AutoConfigurationImportSelector 读取配置清单批量装配;
  • FactoryBean:产出动态生成对象(代理类、客户端桩);
  • 编程式:BeanDefinitionRegistry 直接注册,框架与运行期动态注册场景(规则引擎按规则加载 Bean)。

架构治理视角:注册通道越多,Bean 来源审计越难。我的做法:业务代码只允许前两种;@Import 与编程式是框架和 starter 的专用通道,在代码规约里明确分界——否则半年后没人说得清一个 Bean 从哪来,启动行为变成黑盒。

💻 全栈开发专家 ​

注册 Bean 的方式我数六种:

  1. @Component 系 + @ComponentScan:业务类自己标,最常用
  2. @Bean 方法:配置类里程序化创建,第三方库的类没法加注解只能这么注册
  3. @Import:引入配置类;或 @Import(xxxRegistrar.class) 实现 ImportBeanDefinitionRegistrar 编程注册——MyBatis 的 @MapperScan、@EnableAsync 底层都是这个原理
  4. FactoryBean:getObject() 产物进容器
  5. BeanDefinitionRegistryPostProcessor:最早的扩展点,能动态批量注册 BeanDefinition,框架集成常用
  6. XML:遗留系统专属

给第三方 SDK 封装配置的标准模板:

java
@Configuration
public class SmsConfig {
    @Bean(destroyMethod = "close")
    public SmsClient smsClient(SmsProperties props) {
        return SmsClient.builder().endpoint(props.getEndpoint()).build();
    }
}

destroyMethod 让容器关闭时自动调 close() 释放连接——这是 @Bean 相比手工初始化的隐藏福利(默认还会自动推断 close/shutdown 方法)。答这题时把"什么场景选哪种"讲清楚,比罗列全更有工程味。