Spring Boot 配置类注解@Configuration, @Bean

ai生成,仅做参考

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

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

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

java 复制代码
@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;
    }
}
java 复制代码
@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 的创建逻辑
  1. 对 @Bean 方法的处理方式不同(关键区别!)
  • @Configuration 类中的 @Bean 方法:

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

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

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

  • @Component 类中的 @Bean 方法:

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

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

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

java 复制代码
@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
    }
}
  1. @Configuration 本身已经包含了 @Component:
java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // ← 注意这里!
public @interface Configuration {
    // ...
}
  1. 使用建议

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

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

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

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

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

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

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

对于这个 "管理对象的工厂" 的理解

  1. @Configuration 本身不是工厂,而是 "工厂的蓝图"

Spring 容器(ApplicationContext)才是真正的"对象工厂"

而 @Configuration 标注的类,是 告诉这个工厂:"你要怎么生产某些对象" 的说明书

java 复制代码
@Configuration // ← 这是一份"生产验证码生成器"的配方
public class KaptchaConfig {

    @Bean(name = "captchaProducer")
    public Producer captchaProducer() {
        // 这段代码就是"生产工艺"
        DefaultKaptcha kaptcha = new DefaultKaptcha();
        kaptcha.setConfig(new Config(...));
        return kaptcha; // ← 工厂按此配方生产出一个 Bean
    }
}
  1. 为什么需要这种
    像验证码生成器(DefaultKaptcha)这类对象,不能简单通过 new 就直接使用,它需要:
  • 设置图像宽高
  • 配置字符集、字体、干扰线等参数
  • 将这些参数封装为 Config 对象
  • 调用 setConfig(config) 完成初始化
  • 如果每个地方都手动写一遍,不仅重复,还难以维护。

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

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

java 复制代码
<!-- 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 配置类:

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> 等复杂标签 直接用 ifswitch@Conditional 等 Java 逻辑
集成能力 与 Java 代码割裂 可调用其他方法、使用常量、注入环境变量等

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

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

java 复制代码
# application.yml
kaptcha:
  image:
    width: 200
    height: 80
  text-producer:
    char-string: "0123456789"
    char-length: 4
java 复制代码
// 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; }
}
java 复制代码
// 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,它只是一个"空壳"------必须配合 Spring

Boot 的机制(如 @EnableConfigurationProperties 或 @Component +

@ConfigurationPropertiesScan)才能真正绑定 YAML 配置。

相关推荐
Chase_______2 小时前
【JAVA基础指南(四)】快速掌握类和对象 基础篇
android·java·开发语言
可以简单点2 小时前
spring为什么使用三级缓存而不是两级?
java·spring·缓存
海兰2 小时前
使用 Spring AI 打造企业级 RAG 知识库第三部分:企业部署与优化
java·人工智能·spring
web前端神器2 小时前
宝塔服务器网址ERR_CONNECTION_REFUSED报错排查流程
java·linux·服务器
Cat_Rocky2 小时前
创建LNMRP后端技术栈
java·开发语言
刘 大 望2 小时前
RAG相关技术介绍及Spring AI中使用--第二期
java·人工智能·spring·ai·chatgpt·aigc·etl
CodeSheep2 小时前
宇树科技的最新工资和招人标准
前端·后端·程序员
韩数2 小时前
为了能同时开发多个项目,我烧了几亿 token 开源了一个轻量级 AI-Native IDE
后端·程序员·github