@Bean在@Configuration与@Component中的区别及实例数量探究
嘿,这个问题问到点子上了!很多Spring开发者刚接触这两种Bean声明方式时,都会被CGLIB代理带来的差异搞懵,我来给你拆解清楚:
核心差异:CGLIB代理的影响
@Configuration类的特殊处理:
Spring会给标注了@Configuration的类生成一个CGLIB代理子类。当你在这个类的@Bean方法里调用其他@Bean方法时,代理会拦截这个调用,直接返回Spring容器中已经存在的Bean实例(默认单例),而不是执行方法创建新对象。@Component类的普通处理:
标注@Component的类不会被Spring自动生成CGLIB代理(除非你手动开启了其他代理模式),里面的@Bean方法就是普通的Java方法。如果在同一个@Component类里调用@Bean方法,每次调用都会执行方法体,创建一个全新的实例,和Spring容器中管理的那个实例完全无关。
实例数量对比(默认单例Scope)
1. @Configuration场景
不管你在@Configuration类内部调用多少次@Bean方法,每个@Bean对应的类只会生成1个实例。因为所有的@Bean方法调用都会被代理拦截,复用容器中已有的单例对象。
举个代码例子:
@Configuration public class AppConfig { @Bean public User user() { return new User("Alice"); } @Bean public Order order() { // 这里调用user(),返回的是容器里的同一个User实例 return new Order(user()); } }
运行后,Spring容器中只会有1个User实例和1个Order实例,Order依赖的User就是容器里的那个单例。
2. @Component场景
这种情况要分两种情况看:
- Spring容器初始化时,会调用
@Bean方法创建1个实例并放入容器中; - 如果
@Component类的实例(本身也是Spring管理的单例)内部调用@Bean方法,每次调用都会生成一个新的实例。
还是用代码举例:
@Component public class ComponentBean { @Bean public User user() { return new User("Bob"); } @Bean public Order order() { // 这里调用user(),会创建一个新的User实例,和容器里的那个不是同一个 return new Order(user()); } }
运行后,Spring容器里有1个User实例(初始化时创建的)和1个Order实例,但Order里的User是调用user()方法新创建的,所以User总共有2个实例,Order有1个。如果后续ComponentBean的其他方法再调用user(),还会继续生成新的User实例。
总结一下
| 维度 | @Configuration中的@Bean | @Component中的@Bean |
|---|---|---|
| 是否被CGLIB代理 | 是(自动生成代理类) | 否(默认无代理) |
| 内部@Bean方法调用 | 复用容器单例实例 | 每次调用创建新实例 |
| 默认单例下实例数量 | 每个@Bean对应1个实例 | 容器1个 + 内部调用n个 |
内容的提问来源于stack exchange,提问作者user9328991

