@Bean 和@Component 有什么区别?
- 标签:后端、Spring
🏛 业务架构师
@Bean 和 @Component 都能把对象注册进容器,区别在**"谁负责声明"和"怎么创建"**:
- @Component:标在类上,Spring 调用它的构造器创建,要求你能修改类源码。业务组件的标准姿势;
- @Bean:标在配置类的方法上,创建逻辑由你手写,方法返回什么容器就管什么。适合:
- 第三方库对象:HttpClient、Redisson 客户端、SDK 的 XxxClient,源码不是你的,没法加注解;
- 需要复杂初始化:要读配置、设置拦截器、连接池参数的组装过程;
- 同一类多实例:不同配置产出多个 Bean(主从数据源)。
一个容易被追问的细节:@Bean 方法之间的互调(配置类被 CGLIB 增强)返回的是容器里同一个实例,不是新对象——这是保证配置类内组装一致性的机制。
架构师视角的分层逻辑:@Component 是"我的代码交给容器",@Bean 是"别人的代码我替容器组装"。进一步讲,公司级starter 里清一色 @Bean + @ConditionalOnXxx——平台团队把中间件接入的复杂度封装掉,业务方引依赖即用。这个"注解给业务、方法给平台"的分工,就是我们控制集成成本的核心手段:中间件升级改 starter 一处,几十个业务仓库零改动。
🏗 系统架构师
- @Component(含派生注解):类级声明,「自我描述」的组件,靠类路径扫描发现;
- @Bean:方法级声明,返回值入容器,方法名默认 Bean 名,方法参数即依赖——用于第三方类型(无法加注解)与需要编程逻辑构造的对象(按环境 new 不同实现、构造参数复杂)。
架构层面的差异:
@Bean所在的配置类是装配层,业务类是能力层——分层清晰时,看一个 Config 类就能看清模块的全部外部集成面;proxyBeanMethods:@Configuration默认 true,方法互调走容器保证单例;false(lite 模式)去掉 CGLIB 代理换启动性能,Boot 内部大量使用——这是启动优化时容易被忽略的开关;- AOT/Native 下
@Bean方法在构建期追踪执行,过于动态的编程式逻辑受限——做 GraalVM 支持时这是改造重点。
💻 全栈开发专家
两者都能注册 Bean,差别在使用场景:
- 来源:
@Component标在自家类上靠扫描;@Bean标在配置类方法上,返回值即 Bean - 第三方类:jar 包里的类加不了
@Component,只能@Bean手工装——我的第一判断军规:改不了的类用@Bean - 创建逻辑:
@Bean是纯 Java 代码,可以条件判断、多步构建、按环境返回不同实现;@Component只能反射调构造器 - 生命周期:
@Bean直接声明 initMethod/destroyMethod,还自动推断 close 方法 - 代理模式:
@Bean所在配置类有proxyBeanMethods属性,控制方法互调是否走容器,Boot 自动配置大量利用它提速
java
@Configuration(proxyBeanMethods = false) // lite 模式,启动更快
public class HttpClientConfig {
@Bean(destroyMethod = "close")
public OkHttpClient okHttpClient() {
return new OkHttpClient.Builder()
.connectTimeout(Duration.ofSeconds(2))
.build();
}
}面试要的点:自家类用 @Component、第三方和复杂构造用 @Bean,再补一句 proxyBeanMethods=false 的提速细节,就是有实操的味道。