@Bean、@Confgguration有什么区别?

写一个@Bean放在java component的类里,然后在同一个类里,两次调用这个方法,会怎么样?
spring会创建两个不同的实例,因为每次调用都会执行方法体,给你new一个新的对象出来,这就把Spring的单例控制给破坏了,但如果把这个类上的注解换成configuration,同样两次调用,就会看到一个Bean的实例,为什么因为spring会对configuration,生成cglib的代理对象,这个代理会重写Bean方法,在执行之前先拦截,去容器里查一遍,找到直接返回,找不到才走真正的创建逻辑,所以,表面在调用自己的方法,底层走的是代理,拦截后容器查找,不管调多少次,拿到的都是同一个Bean,这个就是单例的保证,这个机制的本质,就是springAOP的典型应用,用代理来增强方法调用,而普通的component,spring不会对它进行代理,方法调用是最纯粹的java调用,调用一次,就执行一次方法体,
自然就控制不住单例。
总结:configuration会触发cglib代理,保证内部调用,并注解方法的时候,先查容器,实现单例,componet没有这个代理,多次调用就会重复创建。

AI回答:
这是 Spring 非常经典的@Bean 方法内部调用问题,最终表现完全取决于类上标注的是 @Component 还是 @Configuration,二者对应 Spring 两种不同的配置类模式(Lite 轻量模式 / Full 全量模式),单例特性差异巨大。


一、类标注 @Component:多次调用会创建多个实例,单例失效

现象

在 @Component 类中定义 @Bean 方法,同一个类内部多次调用该方法时,每次都会返回一个全新的对象实例,Spring 的单例管理在这里不生效。

底层原理

@Component 中的 @Bean 属于 Lite 轻量配置模式:
Spring 不会对该类生成任何代理对象,类内部的方法调用就是最原生的 Java 方法调用。每次调用 @Bean 方法都会完整执行一遍方法体,直接执行 new 创建对象,完全绕过了 Spring 容器的生命周期管理和单例控制。
相当于脱离了容器、手动创建对象,自然无法保证单例。


二、类标注 @Configuration:多次调用仍为同一单例

现象

换成 @Configuration 后,同一个类里无论调用多少次 @Bean 方法,拿到的始终是同一个单例实例,效果和从容器中 getBean 完全一致。

底层原理

@Configuration 属于 Full 全量配置模式:
Spring 容器启动时,会通过 ConfigurationClassPostProcessor 后置处理器,对所有标注 @Configuration 的类生成 CGLIB 动态代理子类,重写类中所有的 @Bean 方法。

当调用 @Bean 方法时,会先被代理对象拦截:

  1. 先去 Spring 容器中查询对应名称的 Bean 是否已存在;
  2. 若已存在,直接返回容器中的单例实例,不会执行方法体;
  3. 若不存在,才会执行真正的方法体创建 Bean,注册到容器后再返回。

三、本质总结与实践要点

  1. 核心差异:二者的本质区别是是否生成代理对象来管控 @Bean 方法的调用。@Configuration 通过 CGLIB 代理增强了方法语义,@Component 没有代理,就是原生 Java 方法调用。
  2. 设计本质:@Configuration 的代理机制是 Spring AOP 思想的典型应用 —— 专门解决配置类内部 @Bean 方法互相调用时的单例一致性问题。比如 Bean A 依赖 Bean B,直接在方法里调用另一个 @Bean 方法,也能保证拿到的是容器中的单例。
  3. 实践注意:业务组件统一用 @Component,配置类统一用 @Configuration;尽量不要在 @Component 中定义 @Bean 并内部调用,避免意外产生多实例,引发资源浪费或逻辑错误。
posted @ 2026-09-15 16:11  堭鍙銤  阅读(4)  评论(0)    收藏  举报