SpringBoot配置类注解@Configuration, @Bean用法解读

 更新时间:2026年05月02日 14:11:40   作者:han_hanker  
本文通过对比@Component和@Configuration,解释了Spring框架的依赖注入(DI)方式,并介绍了@Configuration和@Bean的方法的用法、特点和区别,举了验证码生成器的例子,介绍了@Configuration如何集中管理Bean的创建逻辑,替代了传统的XML配置

SpringBoot配置类注解@Configuration, @Bean

@Configuration 是 Spring 的核心注解之一,用于:

标识一个类为 配置类(替代传统的 XML 配置文件)

允许在其中通过 @Bean 方法 声明并初始化 Spring 容器中的 Bean

@Configuration
public class KaptchaConfig {

    @Bean(name = "captchaProducer")
    public DefaultKaptcha captchaProducer() {
        Properties props = new Properties();
        props.put("kaptcha.image.width", "200");
        props.put("kaptcha.textproducer.char.string", "0123456789");

        Config config = new Config(props);
        DefaultKaptcha kaptcha = new DefaultKaptcha();
        kaptcha.setConfig(config); // ← 必须手动调用
        return kaptcha;
    }
}
@RestController
public class CaptchaController
{
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;

Java 中使用 Spring 框架的依赖注入(DI)方式,

通过 @Resource 注解按名称注入两个名为 “captchaProducer” 和 “captchaProducerMath” 的 Producer 类型的 Bean。

这个结构是不是眼熟

前面我们讲@Component 和 @Autowired 很像

1、定位不同

在 Spring 框架中,@Configuration 和 @Component 都可以将一个类注册为 Spring 容器中的 Bean,但它们的设计目的、使用场景和内部行为有本质区别。以下是核心对比:

注解用途典型场景
@Component通用组件注解,用于标记任意业务类(如 Service、DAO、Util 等)为 Spring Bean@Service, @Repository, @Controller 都是 @Component 的派生注解
@Configuration专门用于定义配置类,通常包含 @Bean 方法来声明和初始化其他 Bean替代 XML 配置文件,集中管理 Bean 的创建逻辑

2、对 @Bean 方法的处理方式不同(关键区别!)

  • @Configuration 类中的 @Bean 方法:

Spring 会通过 CGLIB 动态代理 增强该类。

当你在同一个配置类中调用另一个 @Bean 方法时,不会创建新对象,而是从 Spring 容器中返回已存在的单例 Bean。

保证了 @Bean 方法的单例语义。

  • @Component 类中的 @Bean 方法:

不会被代理,调用 @Bean 方法相当于普通 Java 方法调用。

每次调用都会创建一个新对象,绕过 Spring 容器的管理。

无法保证单例,可能导致意外的多实例问题。

@Configuration
public class MyConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }

    public void doSomething() {
        // 通过代理,始终返回容器中的同一个实例
        MyService s1 = myService();
        MyService s2 = myService();
        System.out.println(s1 == s2); // true
    }
}

3、@Configuration 本身已经包含了 @Component:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // ← 注意这里!
public @interface Configuration {
    // ...
}

4、使用建议

如果你只是想把一个普通类交给 Spring 管理 → 用 @Component(或其衍生注解)。

如果你要集中定义多个 Bean 的创建逻辑(尤其是需要复用、依赖注入、生命周期控制)→ 必须用 @Configuration。

不要在 @Component 类里写 @Bean 方法,除非你明确知道自己在做什么(且不需要单例)。

@Component 是把一个类变成一个bean

@Configuration 是用@Bean 返回一个对象, 显性的

@Component 是“被管理的对象”,而 @Configuration 是“管理对象的工厂”。

正确使用 @Configuration 能确保 Spring 容器对 Bean 生命周期的完整控制,避免因直接方法调用导致的单例失效问题。

对于这个 “管理对象的工厂” 的理解

1、@Configuration 本身不是工厂,而是 “工厂的蓝图”

Spring 容器(ApplicationContext)才是真正的“对象工厂”而 @Configuration 标注的类,是 告诉这个工厂:“你要怎么生产某些对象” 的说明书

@Configuration // ← 这是一份“生产验证码生成器”的配方
public class KaptchaConfig {

    @Bean(name = "captchaProducer")
    public Producer captchaProducer() {
        // 这段代码就是“生产工艺”
        DefaultKaptcha kaptcha = new DefaultKaptcha();
        kaptcha.setConfig(new Config(...));
        return kaptcha; // ← 工厂按此配方生产出一个 Bean
    }
}

2、为什么需要这种

像验证码生成器(DefaultKaptcha)这类对象,不能简单通过 new 就直接使用,它需要:

  • 设置图像宽高
  • 配置字符集、字体、干扰线等参数
  • 将这些参数封装为 Config 对象
  • 调用 setConfig(config) 完成初始化
  • 如果每个地方都手动写一遍,不仅重复,还难以维护。

而通过 @Configuration + @Bean,你只需 在“工厂蓝图”中定义一次,Spring 容器就会按这个配方 自动生产并管理这个对象。

3、管理对象”的含义

不只是创建,还包括全生命周期控制

功能说明
单例管理默认情况下,@Bean 是单例的,整个应用只创建一次,节省资源
依赖注入如果你的验证码生成器依赖其他 Bean(比如 Redis 缓存),Spring 会自动注入
生命周期回调可以定义 @PostConstruct 初始化或 @PreDestroy 销毁逻辑
AOP 支持可对 Bean 进行代理(如事务、日志、安全控制)
条件化创建通过 @Conditional 等注解,根据环境决定是否创建该对象

4、对比

没有 @Configuration 的“野路子” vs 有 @Configuration 的“工厂模式”

场景手动 new(无工厂)使用 @Configuration(Spring 工厂)
创建方式new DefaultKaptcha() 到处写在配置类中集中定义一次
配置修改每处都要改代码只改 @Configuration 类或外部配置文件
多实例支持难以区分不同类型的验证码通过不同 @Bean(name=...) 轻松支持
测试难以 mock 或替换可通过 Spring Test 替换 Bean
与框架集成孤立对象,无法享受 Spring 生态自动参与事务、缓存、安全等

直接写new DefaultKaptcha()

  • 重复初始化(每次 HTTP 请求都新建对象)
  • 无法统一管理配置
  • 不能被 Spring 管理(比如不能注入到其他 Service)

@Configuration 配置类 是替代传统 XML 配置的核心载体这句怎么理解

在早期 Spring(如 Spring 2.x/3.x),所有 Bean 的定义和依赖关系都写在 XML 文件中,例如:

<!-- applicationContext.xml -->
<beans>
    <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
        <property name="config">
            <bean class="com.google.code.kaptcha.util.Config">
                <constructor-arg>
                    <props>
                        <prop key="kaptcha.image.width">200</prop>
                        <prop key="kaptcha.textproducer.char.string">0123456789</prop>
                    </props>
                </constructor-arg>
            </bean>
        </property>
    </bean>
</beans>

Spring 3.0 引入了 基于 Java 的配置(Java-based Configuration),核心就是 @Configuration + @Bean。

上面的 XML 等价于以下 Java 配置类:

@Configuration
public class KaptchaConfig {

    @Bean(name = "captchaProducer")
    public DefaultKaptcha captchaProducer() {
        Properties props = new Properties();
        props.setProperty("kaptcha.image.width", "200");
        props.setProperty("kaptcha.textproducer.char.string", "0123456789");

        Config config = new Config(props);
        DefaultKaptcha kaptcha = new DefaultKaptcha();
        kaptcha.setConfig(config);
        return kaptcha;
    }
}
维度XML 配置@Configuration 配置类
本质外部配置文件(字符串)Java 类(强类型)
可读性嵌套深、冗长逻辑清晰、代码即文档
安全性无编译时检查(拼错 key 不报错)编译时报错(方法名、类型错误立刻暴露)
重构支持IDE 难以追踪引用支持重命名、查找引用、跳转定义
灵活性条件逻辑需用 <profile> 等复杂标签直接用 if、switch、@Conditional 等 Java 逻辑
集成能力与 Java 代码割裂可调用其他方法、使用常量、注入环境变量等

将 @Configuration 与 @ConfigurationProperties 结合使用,并绑定到 application.yml,是 Spring Boot 实现“外部化配置 + 类型安全注入”的核心模式

假设你想让验证码的宽度、高度、字符集等可配置,而不是硬编码在 Java 里

# application.yml
kaptcha:
  image:
    width: 200
    height: 80
  text-producer:
    char-string: "0123456789"
    char-length: 4
// src/main/java/com/example/config/KaptchaProperties.java
package com.example.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "kaptcha")
public class KaptchaProperties {

    private Image image = new Image();
    private TextProducer textProducer = new TextProducer();

    // 嵌套类:对应 YAML 中的 kaptcha.image
    public static class Image {
        private int width = 200;
        private int height = 80;

        // Getters & Setters
        public int getWidth() { return width; }
        public void setWidth(int width) { this.width = width; }
        public int getHeight() { return height; }
        public void setHeight(int height) { this.height = height; }
    }

    // 嵌套类:对应 YAML 中的 kaptcha.text-producer
    public static class TextProducer {
        private String charString = "0123456789";
        private int charLength = 4;

        public String getCharString() { return charString; }
        public void setCharString(String charString) { this.charString = charString; }
        public int getCharLength() { return charLength; }
        public void setCharLength(int charLength) { this.charLength = charLength; }
    }

    // 外层 Getters & Setters
    public Image getImage() { return image; }
    public void setImage(Image image) { this.image = image; }
    public TextProducer getTextProducer() { return textProducer; }
    public void setTextProducer(TextProducer textProducer) { this.textProducer = textProducer; }
}
// src/main/java/com/example/config/KaptchaConfig.java
package com.example.config;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import java.util.Properties;

@Configuration
@EnableConfigurationProperties(KaptchaProperties.class) // 启用 KaptchaProperties
public class KaptchaConfig {

    @Bean(name = "captchaProducer")
    public DefaultKaptcha captchaProducer(KaptchaProperties props) {
        // 从 props 读取配置
        Properties properties = new Properties();
        properties.put("kaptcha.image.width", String.valueOf(props.getImage().getWidth()));
        properties.put("kaptcha.image.height", String.valueOf(props.getImage().getHeight()));
        properties.put("kaptcha.textproducer.char.string", props.getTextProducer().getCharString());
        properties.put("kaptcha.textproducer.char.length", String.valueOf(props.getTextProducer().getCharLength()));

        // 创建并配置 Kaptcha
        Config config = new Config(properties);
        DefaultKaptcha kaptcha = new DefaultKaptcha();
        kaptcha.setConfig(config);

        return kaptcha;
    }
}
  • @EnableConfigurationProperties(KaptchaProperties.class):告诉 Spring “请加载这个配置属性类”
  • captchaProducer(KaptchaProperties props):Spring 自动注入已绑定好值的 KaptchaProperties 实例
  • 所有配置来自 application.yml,无需硬编码

public class KaptchaProperties 这个类 怎么没用yml的配置?

KaptchaProperties 这个类 本身不会自动读取 application.yml,它只是一个“空壳”——必须配合 SpringBoot 的机制(如 @EnableConfigurationProperties 或 @Component +@ConfigurationPropertiesScan)才能真正绑定 YAML 配置。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • springcloud LogBack日志使用详解

    springcloud LogBack日志使用详解

    这篇文章主要介绍了springcloud LogBack日志使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Spring Boot 初始化运行特定方法解析

    Spring Boot 初始化运行特定方法解析

    这篇文章主要介绍了Spring Boot 初始化运行特定方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java注释和关键字实例详解

    Java注释和关键字实例详解

    注释是对程序语言的说明,有助于开发者和用户之间的交流,方便理解程序,注释不是编程语句,因此被编译器忽略,下面这篇文章主要给大家介绍了关于Java注释和关键字的相关资料,需要的朋友可以参考下
    2023-01-01
  • java线程池参数自定义设置详解

    java线程池参数自定义设置详解

    这篇文章主要为大家介绍了java线程池参数自定义设置详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Java中的Phaser并发阶段器详解

    Java中的Phaser并发阶段器详解

    这篇文章主要介绍了Java中的Phaser并发阶段器详解,Phaser由JDK1.7提出,是一个复杂强大的同步辅助类,是对同步工具类CountDownLatch和CyclicBarrier的综合升级,能够支持分阶段实现等待的业务场景,需要的朋友可以参考下
    2023-12-12
  • Java Elastic Job动态添加任务实现过程解析

    Java Elastic Job动态添加任务实现过程解析

    这篇文章主要介绍了Java Elastic Job动态添加任务实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • SpringBoot结合Ajax实现登录页面实例

    SpringBoot结合Ajax实现登录页面实例

    大家好,本篇文章主要讲的是SpringBoot结合Ajax实现登录页面实例,感兴趣的同学赶快来看一看,对你有帮助的话记得收藏一下
    2022-02-02
  • Maven项src/main/java目录下配置文件无法被导出或者生效的问题和处理方案

    Maven项src/main/java目录下配置文件无法被导出或者生效的问题和处理方案

    这篇文章主要介绍了Maven项src/main/java目录下配置文件无法被导出或者生效的问题和处理方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • springboot 整合sentinel的示例代码

    springboot 整合sentinel的示例代码

    本文主要介绍了springboot 整合sentinel的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 第一次使用Android Studio时你应该知道的一切配置(推荐)

    第一次使用Android Studio时你应该知道的一切配置(推荐)

    这篇文章主要介绍了第一次使用Android Studio时你应该知道的一切配置(推荐) ,需要的朋友可以参考下
    2017-09-09

最新评论