java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot配置类注解@Configuration, @Bean

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

作者: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 方法的处理方式不同(关键区别!)

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

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

保证了 @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 就直接使用,它需要:

而通过 @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()

@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;
    }
}

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

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

总结

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

您可能感兴趣的文章:
阅读全文