一句话核心结论
@Component/@Service/@Controller:扫描类本身,把这个类直接作为Bean ,适合你自己写的业务代码,类源码你能改。
@Configuration + @Bean:通过方法返回对象来注册Bean ,适合你没法修改源码 的第三方类,或者需要复杂构造、动态创建对象的场景。
注意:
@Service/@Controller本质都是@Component的派生注解,功能上一样,只是语义区分。
一、两种方式对比
方式1:@Component家族(组件扫描)
java
@Service
public class UserService {
}
- 原理:Spring启动时包扫描,扫描到标记注解的类,自动实例化这个类,放到IOC容器。
✅ 优点:简单,一行注解搞定,日常业务开发首选
❌ 限制:必须能修改这个类的源代码,才能在类上加注解。
如果这个类是第三方jar包里的(比如RedisTemplate、RestTemplate、MyBatis的某些类),你拿不到源码,不可能去源码上加
@Component。
方式2:@Configuration + @Bean
java
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate(){
// 可以自定义配置参数
return new RestTemplate();
}
}
- 原理:
@Configuration标记这是配置类,Spring会执行里面带@Bean的方法,把方法返回值注册成Bean 。
✅ 优点:
- 不需要修改目标类源码,第三方类也能注册到容器
- 创建Bean前可以写自定义逻辑:设置参数、装配依赖、条件判断
- 一个配置方法可以灵活控制实例创建过程
❌ 缺点:代码多一点
二、什么时候必须用 @Bean
-
引入第三方组件(最常见)
比如
RestTemplate、RedisTemplate、线程池、连接池,类在jar包中,源码不能改,无法加@Component,只能用@Bean创建。 -
Bean创建需要复杂初始化逻辑
创建对象时要设置很多参数、调用初始化方法、根据配置文件动态选择实现类。
java
@Bean
public DataSource dataSource(){
HikariConfig config = new HikariConfig();
config.setJdbcUrl("xxx");
config.setMaximumPoolSize(20);
return new HikariDataSource(config);
}
这种复杂构建,直接@Component很难实现。
- 同一类型,需要多个不同实例
比如需要两个不同配置的线程池,同一个类要生成多个Bean,用@Component只能一个,@Bean可以写多个方法,配合@Qualifier区分。
三、什么时候优先用 @Component / @Service / @Controller
- 自己开发的业务类:Service、Controller、Mapper
- 对象创建逻辑简单:无特殊构造参数,直接new就可以使用
四、补充一个容易踩坑点:@Configuration 的 Full模式
@Configuration 默认Full模式,会对@Bean方法做CGLIB代理。
配置类里面多个@Bean方法互相调用时,不会重复new对象,会直接从容器拿单例Bean。
如果写成
@Configuration(proxyBeanMethods = false)(轻量模式),就不会代理,内部方法调用会生成新对象。
五、极简总结
- 自己写的代码,源码可控 → @Component系列,简单省事
- 第三方类 / 复杂对象构建 / 多实例 → @Configuration + @Bean
两者不是替代关系,是互补关系,SpringBoot项目里一般是同时混用。