对比 @Configuration(Full) vs @Component(Lite)

核心现象:同一个类里面,@Bean方法互相调用,Full拿单例,Lite新建对象

1. 两个简单Bean

java 复制代码
public class ABean {
}

public class BBean {
    public ABean aBean;
    public BBean(ABean aBean) {
        this.aBean = aBean;
    }
}

2. Full模式(@Configuration)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration // Full模式,CGLIB代理
public class FullConfig {

    @Bean
    public ABean aBean() {
        System.out.println("Full -> 创建ABean");
        return new ABean();
    }

    @Bean
    public BBean bBean() {
        // 在配置类内部调用 aBean()
        ABean a = aBean();
        return new BBean(a);
    }
}

3. Lite模式(@Component + @Bean)

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component // Lite模式,无CGLIB代理
public class LiteConfig {

    @Bean
    public ABean aBean() {
        System.out.println("Lite -> 创建ABean");
        return new ABean();
    }

    @Bean
    public BBean bBean() {
        // 普通java方法调用!
        ABean a = aBean();
        return new BBean(a);
    }
}

4. 启动类 & 测试

java 复制代码
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class BeanDemoApp implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(BeanDemoApp.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        ApplicationContext ctx = BeanDemoApp.this;

        // FullConfig
        BBean fullB = ctx.getBean("bBean", BBean.class);
        ABean fullA = ctx.getBean("aBean", ABean.class);
        System.out.println("Full模式:bBean里面的aBean 和容器aBean是否同一个:" + (fullB.aBean == fullA));

        // LiteConfig
        BBean liteB = ctx.getBean("liteConfig.bBean", BBean.class);
        ABean liteA = ctx.getBean("liteConfig.aBean", ABean.class);
        System.out.println("Lite模式:bBean里面的aBean 和容器aBean是否同一个:" + (liteB.aBean == liteA));
    }
}

控制台输出结果

复制代码
Full -> 创建ABean
Full模式:bBean里面的aBean 和容器aBean是否同一个:true

Lite -> 创建ABean
Lite -> 创建ABean
Lite模式:bBean里面的aBean 和容器aBean是否同一个:false

解读

  1. Full(@Configuration)

    bBean()里调用aBean(),不是直接执行方法,而是被代理拦截,从Spring容器返回已存在的单例,只实例化一次。

  2. Lite(@Component + @Bean)

    没有代理,bBean()调用aBean()就是普通Java方法执行,new了两次ABean :一次是bBean构造用的,一次是Spring扫描@Bean注册的,两个对象地址不一样。

⚠️ 注意:如果不通过内部方法调用 ,只是单独定义一堆互不引用的@Bean,Lite模式看起来一切正常,坑藏在内部互相调用场景。

补充:Spring 6 / SpringBoot3 新变化

Spring6 引入 @Configuration(proxyBeanMethods = false)

java 复制代码
@Configuration(proxyBeanMethods = false)
public class Config {
    @Bean
    ...
}

这个也是Lite模式 !

虽然写了@Configuration,但是关闭代理,内部方法调用同样会新建对象。

现在SpringBoot很多自动配置都用这个,好处:不需要CGLIB,启动更快,代价就是不能内部调用@Bean方法。


相关推荐
最强小杰1 分钟前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
Flynn Liang17 分钟前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai
灿飞24 分钟前
Kotlin与Java虚拟机六:基础与类型系统:一切皆对象,但对象有代价
java·kotlin
计算机毕设定制辅导-无忧学长33 分钟前
《基于微信小程序健康习惯激励系统设计与实现》
java·spring boot·mysql·微信小程序·uniapp·健康习惯激励系统
揽星河..38 分钟前
【C语言】指针
c语言·开发语言
小小数媒成员1 小时前
UGUI原理(一)
开发语言·游戏·unity·游戏引擎
速易达网络1 小时前
Three.js 动画入门教学:从场景搭建到流畅动效
开发语言·javascript·ecmascript
福大大架构师每日一题1 小时前
excelize v2.11.1发布:Go 1.26.0起步,16项安全修复与嵌入对象能力全面升级
开发语言·安全·golang
Sarvartha1 小时前
集合概述 & Collection 接口
开发语言
雪芽蓝域zzs1 小时前
第 1 章:IDEA 创建 SpringBoot3.5.16 Maven 项目
java·maven·intellij-idea