Spring Bean 注册到容器有哪些方式?
- 标签:后端、Spring
🏛 业务架构师
Spring Bean 注册到容器的方式,按"声明主体"分四类:
- 注解声明 + 组件扫描:
@Component/@Service/@Repository/@Controller标注类,@ComponentScan指定包路径扫描。业务代码的主力方式; @Bean方法:配置类中显式定义,适合第三方 SDK 对象(你没有源码加不了注解)和需要自定义构造逻辑的场景;@Import导入:直接导入配置类、普通类,或实现ImportSelector/ImportBeanDefinitionRegistrar编程式批量注册——Spring Boot 自动配置的底层机制(@EnableAutoConfiguration通过 Registrar 加载AutoConfiguration.imports清单);- 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 的方式我数六种:
@Component系 +@ComponentScan:业务类自己标,最常用@Bean方法:配置类里程序化创建,第三方库的类没法加注解只能这么注册@Import:引入配置类;或@Import(xxxRegistrar.class)实现ImportBeanDefinitionRegistrar编程注册——MyBatis 的@MapperScan、@EnableAsync底层都是这个原理FactoryBean:getObject()产物进容器BeanDefinitionRegistryPostProcessor:最早的扩展点,能动态批量注册 BeanDefinition,框架集成常用- 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 方法)。答这题时把"什么场景选哪种"讲清楚,比罗列全更有工程味。