Spring中@Configuration与@Bean底层原理详解


在 Spring / Spring Boot 项目中,我们经常会写这样的代码:

@Configuration
public class RestConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

很多初学者都会有一个疑问:

@Bean 方法是不是每次注入都会执行一次?
@Autowired 注入的是不是新对象?

本文带你彻底搞清楚。


一、Spring 容器是如何处理 @Configuration 的?

1️⃣ 启动流程

Spring 启动时会:

  1. 扫描带有 @Configuration 的类
  2. 解析其中的 @Bean 方法
  3. 执行 @Bean 方法
  4. 将返回值注册进 IoC 容器

简化理解如下:

public class SpringContainer {

    private Map<String, Object> singletonObjects = new HashMap<>();

    public void initialize() {
        RestConfig config = new RestConfig();
        Object bean = config.restTemplate();  // 执行一次
        singletonObjects.put("restTemplate", bean);
    }

    public Object getBean(String name) {
        return singletonObjects.get(name);
    }
}

二、默认是单例模式(非常重要)

Spring Bean 默认作用域:

singleton(单例)

示例:

@Service
public class OrderService {

    @Autowired
    private RestTemplate restTemplate1;

    @Autowired
    private RestTemplate restTemplate2;

    public void test() {
        System.out.println(restTemplate1 == restTemplate2);
    }
}

输出:

true

说明:

注入的是同一个 Bean 实例。


三、如何验证 @Bean 只执行一次?

@Configuration
public class RestConfig {

    private int counter = 0;

    @Bean
    public RestTemplate restTemplate() {
        counter++;
        System.out.println("创建次数:" + counter);
        return new RestTemplate();
    }
}

启动时只会输出一次:

创建次数:1

四、生命周期流程图

Spring启动
    ↓
扫描@Configuration
    ↓
执行@Bean方法
    ↓
放入单例池
    ↓
@Autowired 从容器获取

五、如果想每次获取都是新对象?

使用 prototype 作用域:

@Bean
@Scope("prototype")
public RestTemplate restTemplate() {
    return new RestTemplate();
}

验证:

@Autowired
private ApplicationContext context;

public void test() {
    RestTemplate r1 = context.getBean(RestTemplate.class);
    RestTemplate r2 = context.getBean(RestTemplate.class);
    System.out.println(r1 == r2);
}

输出:

false

六、@Configuration 的 CGLIB 代理机制(进阶)

如果你在配置类中调用另一个 @Bean 方法:

@Bean
public A a() {
    return new A(b());
}

@Bean
public B b() {
    return new B();
}

Spring 会通过 CGLIB 代理增强配置类,保证:

即使在内部方法调用,也不会重复创建 Bean。


七、总结

✅ @Bean 方法默认只执行一次
✅ 默认作用域是 singleton
✅ @Autowired 获取的是容器中的对象
✅ prototype 需要显式声明
✅ @Configuration 会被 CGLIB 增强

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐