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
相关推荐
2601_962071577 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
zww89491118 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·eclipse
INS_KF8 小时前
【编程笔记】成员函数中两个 const 的区别(const Data &getData() const;)
前端·javascript·笔记
tju新生代魔迷10 小时前
Verilog HDL 学习笔记(十三)| 第13章 编程语言接口(PLI)
笔记·学习
zww894911111 小时前
匿名树洞系统开发实战:从需求分析到部署指南
java·eclipse
行百里er11 小时前
Gateway 上别硬塞 MVC:DeferredImportSelector 看菜下锅
spring boot·后端·开源
点心的游戏开发世界11 小时前
UnityShaderGraph滚动UV笔记
笔记·uv
瑞码空间11 小时前
git知识点黄金笔记
笔记·git·elasticsearch
黑马程序员毕设12 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
木井巳12 小时前
【BFS/DFS 解决 FloodFill 算法】太平洋大西洋水流问题
java·算法·leetcode·深度优先·广度优先·宽度优先·推荐算法