# @Configuration与@Component区别是什么?
在 Spring 框架中,@Configuration 和 @Component 都是用于将类定义为 Spring 容器的 Bean,但它们在用途和行为上有显著区别。
# 基本定位
@Component:通用的组件注解。当一个类被标记为@Component(或其派生注解@Service、@Repository、@Controller),Spring 会将其作为一个普通的 Bean 注册到容器中。它适合那些不承担特殊配置职责的普通业务类。@Configuration:配置类注解。它本身被@Component元注解修饰,所以@Configuration类也是一个 Spring Bean。但它的核心职责是定义 Bean 的创建逻辑——通常通过@Bean方法暴露 Bean 实例。
# @Bean 方法的行为差异(最关键的区别)
当一个类中使用 @Bean 方法定义 Bean 时:
- 在
@Configuration类中:这些@Bean方法会被 Spring 通过 CGLIB 动态代理 增强。这意味着:- 即使你在方法内部多次调用其他
@Bean方法,返回的始终是同一个容器管理的单例实例(默认单例作用域)。 - 保证了 Bean 之间的依赖关系符合预期的单例语义。
- 即使你在方法内部多次调用其他
- 在普通
@Component类中:@Bean方法不会被代理。如果在一个@Component类中调用另一个@Bean方法,那只是一个普通的 Java 方法调用,每次都会新建实例,破坏了单例语义。
示例对比
@Configuration
public class ConfigClass {
@Bean
public A a() {
return new A();
}
@Bean
public B b() {
// 通过方法调用获取 A → 由于代理,实际从容器中获取单例的 A
return new B(a());
}
}
@Component
public class ComponentClass {
@Bean
public A a() {
return new A();
}
@Bean
public B b() {
// 这里是普通 Java 调用,会创建新的 A 实例,不是容器中的单例
return new B(a());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在 ComponentClass 中,b() 方法里调用 a() 会生成一个新的 A 对象,而不是容器中已注册的那个。
# 使用场景
@Configuration:专门用于配置类,集中管理一组 Bean 的定义,特别是当 Bean 之间有复杂依赖或需要保证单例时。通常配合@Bean、@Import、@PropertySource等使用。@Component:用于普通的自动检测类(如服务、DAO、控制器)。如果需要在普通组件中通过@Bean定义对象,通常是违反设计直觉的,更推荐使用@Configuration。
# 内部处理的差异
- Spring 在处理
@Configuration时会创建 CGLIB 代理子类,拦截@Bean方法的调用,确保 Bean 的生命周期管理。 @Component不会进行这种代理处理,因此性能开销略小,但牺牲了@Bean方法的拦截能力。
# 总结表
| 特性 | @Configuration | @Component |
|---|---|---|
自身是否被 @Component 元注解 | 是 | 是(被其他注解间接使用) |
| 主要用途 | 定义 Bean 配置类 | 标记普通组件类 |
@Bean 方法行为 | 被 CGLIB 代理,保证单例 | 普通方法调用,不保证单例 |
是否推荐使用 @Bean | 强烈推荐,标准用法 | 可以,但非典型,容易出错 |
| 典型场景 | @Configuration + @Bean | @Service、@Repository 等 |
一句话概括:@Configuration 是专门用于配置 Bean 定义的增强型组件,它通过代理保证了 @Bean 方法的单例语义;而 @Component 是通用的普通组件注解,不具备这种特殊处理。