Spring Boot `@Configuration` 与 `@Component` 笔记

Spring Boot @Configuration@Component 笔记

1️⃣ 基本概念

注解 作用 是否有代理 适用场景
@Component 标记普通组件,将类交给 Spring 容器管理 ❌ 没有 CGLIB 代理 普通 Bean,工具类、过滤器、监听器等
@Configuration 标记配置类,用来声明 @Bean ✅ 有 CGLIB 代理 声明 Bean,保证同一个 @Bean 方法多次调用返回同一个对象

2️⃣ 单例与代理机制

Spring 中的 Bean 默认是单例的

  1. 直接注入 Bean(@Autowired

    java 复制代码
    @Autowired
    private MyService myServiceA;
    
    @Autowired
    private MyService myServiceB;
    • 容器中只有一份 MyService 实例
    • 无论注入多少次,拿到的都是同一个对象
    • 和配置类是否用代理无关
  2. 通过配置类方法调用 Bean

    java 复制代码
    MyService s1 = configA.myServiceA();
    MyService s2 = configA.myServiceA();
    
    MyService s3 = configB.myServiceB();
    MyService s4 = configB.myServiceB();
    • @Configuration 的类被 Spring 生成了 CGLIB 代理

      • 每次调用 myServiceA() → 代理先检查容器
      • 容器已有实例就直接返回 → s1 == s2
    • @Component 的类没有代理

      • 每次调用 myServiceB() → 都是 new 一个新对象 → s3 != s4

3️⃣ Demo 代码

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

// 业务类
@Service
public class MyService {
}

// 配置类 A
@Configuration
public class ConfigA {

    @Bean
    public MyService myServiceA() {
        return new MyService();
    }
}

// 配置类 B,用 Component 替代 Configuration
@Component
public class ConfigB {

    @Bean
    public MyService myServiceB() {
        return new MyService();
    }
}

// 测试 Runner
@Component
public class TestRunner implements CommandLineRunner {

    @Autowired
    private ConfigA configA;

    @Autowired
    private ConfigB configB;

    @Autowired
    private MyService myServiceA;

    @Autowired
    private MyService myServiceB;

    @Override
    public void run(String... args) throws Exception {

        System.out.println("从容器拿到 myServiceA: " + myServiceA);
        System.out.println("从容器拿到 myServiceB: " + myServiceB);

        // 调用配置类方法
        MyService s1 = configA.myServiceA();
        MyService s2 = configA.myServiceA();

        MyService s3 = configB.myServiceB();
        MyService s4 = configB.myServiceB();

        System.out.println("ConfigA.myServiceA() 两次调用是否同一对象: " + (s1 == s2)); // true
        System.out.println("ConfigB.myServiceB() 两次调用是否同一对象: " + (s3 == s4)); // false
    }
}

4️⃣ 结论

  1. 注入 Bean → 拿到的都是容器里的单例

  2. 调用配置类方法

    • @Configuration → 通过代理保证单例
    • @Component → 没有代理,每次调用返回新对象
  3. 如果想保证通过方法调用也返回单例,必须使用 @Configuration


5️⃣ 小贴士

  • 不要把 @Configuration 写成 @Component,否则通过配置类方法调用 Bean 可能产生多个对象

  • Bean 名称冲突可以通过 @Bean("myBeanName") 或开启覆盖:

    yaml 复制代码
    spring.main.allow-bean-definition-overriding=true
相关推荐
会编程的土豆8 分钟前
Redis 常用操作笔记(Go 开发实战)
redis·笔记·golang
Rsingstarzengjx9 分钟前
【stm32】尚硅谷基础篇笔记
笔记·stm32·嵌入式硬件
JP-Destiny10 分钟前
docker-安装redis
java·redis·docker
weixin_BYSJ198712 分钟前
基于Django的非物质文化遗产管理系统设计与实现(源码 + 文档)98950
java·javascript·spring boot·python·django·flask·php
AOwhisky13 分钟前
Ceph系列第五期:Ceph 对象存储(RADOS Gateway)精讲
linux·运维·笔记·ceph·gateway·对象存储
凉、介16 分钟前
深入理解 ARMv8-A|异常/中断处理
笔记·学习·嵌入式·arm
小张小张爱学习17 分钟前
JVM高频面试题
java·jvm
轻刀快马17 分钟前
重塑 Java 世界的两根支柱:穿透 Spring IoC 与 AOP 的架构哲学
java·spring·架构
云烟成雨TD20 分钟前
Spring AI Alibaba 1.x 系列【68】Graph SSE 流式输出
java·人工智能·spring
東隅已逝,桑榆非晚21 分钟前
新手入门指南:认识 C 语言文件操作(下)
c语言·笔记