SpringBoot配置類注解@Configuration, @Bean用法解讀
SpringBoot配置類注解@Configuration, @Bean
@Configuration 是 Spring 的核心注解之一,用于:
標(biāo)識(shí)一個(gè)類為 配置類(替代傳統(tǒng)的 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); // ← 必須手動(dòng)調(diào)用
return kaptcha;
}
}
@RestController
public class CaptchaController
{
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;
Java 中使用 Spring 框架的依賴注入(DI)方式,
通過 @Resource 注解按名稱注入兩個(gè)名為 “captchaProducer” 和 “captchaProducerMath” 的 Producer 類型的 Bean。
這個(gè)結(jié)構(gòu)是不是眼熟
前面我們講@Component 和 @Autowired 很像
1、定位不同
在 Spring 框架中,@Configuration 和 @Component 都可以將一個(gè)類注冊(cè)為 Spring 容器中的 Bean,但它們的設(shè)計(jì)目的、使用場(chǎng)景和內(nèi)部行為有本質(zhì)區(qū)別。以下是核心對(duì)比:
| 注解 | 用途 | 典型場(chǎng)景 |
|---|---|---|
| @Component | 通用組件注解,用于標(biāo)記任意業(yè)務(wù)類(如 Service、DAO、Util 等)為 Spring Bean | @Service, @Repository, @Controller 都是 @Component 的派生注解 |
| @Configuration | 專門用于定義配置類,通常包含 @Bean 方法來聲明和初始化其他 Bean | 替代 XML 配置文件,集中管理 Bean 的創(chuàng)建邏輯 |
2、對(duì) @Bean 方法的處理方式不同(關(guān)鍵區(qū)別!)
- @Configuration 類中的 @Bean 方法:
Spring 會(huì)通過 CGLIB 動(dòng)態(tài)代理 增強(qiáng)該類。
當(dāng)你在同一個(gè)配置類中調(diào)用另一個(gè) @Bean 方法時(shí),不會(huì)創(chuàng)建新對(duì)象,而是從 Spring 容器中返回已存在的單例 Bean。
保證了 @Bean 方法的單例語義。
- @Component 類中的 @Bean 方法:
不會(huì)被代理,調(diào)用 @Bean 方法相當(dāng)于普通 Java 方法調(diào)用。
每次調(diào)用都會(huì)創(chuàng)建一個(gè)新對(duì)象,繞過 Spring 容器的管理。
無法保證單例,可能導(dǎo)致意外的多實(shí)例問題。
@Configuration
public class MyConfig {
@Bean
public MyService myService() {
return new MyService();
}
public void doSomething() {
// 通過代理,始終返回容器中的同一個(gè)實(shí)例
MyService s1 = myService();
MyService s2 = myService();
System.out.println(s1 == s2); // true
}
}
3、@Configuration 本身已經(jīng)包含了 @Component:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // ← 注意這里!
public @interface Configuration {
// ...
}
4、使用建議
如果你只是想把一個(gè)普通類交給 Spring 管理 → 用 @Component(或其衍生注解)。
如果你要集中定義多個(gè) Bean 的創(chuàng)建邏輯(尤其是需要復(fù)用、依賴注入、生命周期控制)→ 必須用 @Configuration。
不要在 @Component 類里寫 @Bean 方法,除非你明確知道自己在做什么(且不需要單例)。
@Component 是把一個(gè)類變成一個(gè)bean
@Configuration 是用@Bean 返回一個(gè)對(duì)象, 顯性的
@Component 是“被管理的對(duì)象”,而 @Configuration 是“管理對(duì)象的工廠”。
正確使用 @Configuration 能確保 Spring 容器對(duì) Bean 生命周期的完整控制,避免因直接方法調(diào)用導(dǎo)致的單例失效問題。
對(duì)于這個(gè) “管理對(duì)象的工廠” 的理解
1、@Configuration 本身不是工廠,而是 “工廠的藍(lán)圖”
Spring 容器(ApplicationContext)才是真正的“對(duì)象工廠”而 @Configuration 標(biāo)注的類,是 告訴這個(gè)工廠:“你要怎么生產(chǎn)某些對(duì)象” 的說明書
@Configuration // ← 這是一份“生產(chǎn)驗(yàn)證碼生成器”的配方
public class KaptchaConfig {
@Bean(name = "captchaProducer")
public Producer captchaProducer() {
// 這段代碼就是“生產(chǎn)工藝”
DefaultKaptcha kaptcha = new DefaultKaptcha();
kaptcha.setConfig(new Config(...));
return kaptcha; // ← 工廠按此配方生產(chǎn)出一個(gè) Bean
}
}
2、為什么需要這種
像驗(yàn)證碼生成器(DefaultKaptcha)這類對(duì)象,不能簡(jiǎn)單通過 new 就直接使用,它需要:
- 設(shè)置圖像寬高
- 配置字符集、字體、干擾線等參數(shù)
- 將這些參數(shù)封裝為 Config 對(duì)象
- 調(diào)用 setConfig(config) 完成初始化
- 如果每個(gè)地方都手動(dòng)寫一遍,不僅重復(fù),還難以維護(hù)。
而通過 @Configuration + @Bean,你只需 在“工廠藍(lán)圖”中定義一次,Spring 容器就會(huì)按這個(gè)配方 自動(dòng)生產(chǎn)并管理這個(gè)對(duì)象。
3、管理對(duì)象”的含義
不只是創(chuàng)建,還包括全生命周期控制
| 功能 | 說明 |
|---|---|
| 單例管理 | 默認(rèn)情況下,@Bean 是單例的,整個(gè)應(yīng)用只創(chuàng)建一次,節(jié)省資源 |
| 依賴注入 | 如果你的驗(yàn)證碼生成器依賴其他 Bean(比如 Redis 緩存),Spring 會(huì)自動(dòng)注入 |
| 生命周期回調(diào) | 可以定義 @PostConstruct 初始化或 @PreDestroy 銷毀邏輯 |
| AOP 支持 | 可對(duì) Bean 進(jìn)行代理(如事務(wù)、日志、安全控制) |
| 條件化創(chuàng)建 | 通過 @Conditional 等注解,根據(jù)環(huán)境決定是否創(chuàng)建該對(duì)象 |
4、對(duì)比
沒有 @Configuration 的“野路子” vs 有 @Configuration 的“工廠模式”
| 場(chǎng)景 | 手動(dòng) new(無工廠) | 使用 @Configuration(Spring 工廠) |
|---|---|---|
| 創(chuàng)建方式 | new DefaultKaptcha() 到處寫 | 在配置類中集中定義一次 |
| 配置修改 | 每處都要改代碼 | 只改 @Configuration 類或外部配置文件 |
| 多實(shí)例支持 | 難以區(qū)分不同類型的驗(yàn)證碼 | 通過不同 @Bean(name=...) 輕松支持 |
| 測(cè)試 | 難以 mock 或替換 | 可通過 Spring Test 替換 Bean |
| 與框架集成 | 孤立對(duì)象,無法享受 Spring 生態(tài) | 自動(dòng)參與事務(wù)、緩存、安全等 |
直接寫new DefaultKaptcha()
- 重復(fù)初始化(每次 HTTP 請(qǐng)求都新建對(duì)象)
- 無法統(tǒng)一管理配置
- 不能被 Spring 管理(比如不能注入到其他 Service)
@Configuration 配置類 是替代傳統(tǒng) XML 配置的核心載體這句怎么理解
在早期 Spring(如 Spring 2.x/3.x),所有 Bean 的定義和依賴關(guān)系都寫在 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 等價(jià)于以下 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 配置類 |
|---|---|---|
| 本質(zhì) | 外部配置文件(字符串) | Java 類(強(qiáng)類型) |
| 可讀性 | 嵌套深、冗長(zhǎng) | 邏輯清晰、代碼即文檔 |
| 安全性 | 無編譯時(shí)檢查(拼錯(cuò) key 不報(bào)錯(cuò)) | 編譯時(shí)報(bào)錯(cuò)(方法名、類型錯(cuò)誤立刻暴露) |
| 重構(gòu)支持 | IDE 難以追蹤引用 | 支持重命名、查找引用、跳轉(zhuǎn)定義 |
| 靈活性 | 條件邏輯需用 <profile> 等復(fù)雜標(biāo)簽 | 直接用 if、switch、@Conditional 等 Java 邏輯 |
| 集成能力 | 與 Java 代碼割裂 | 可調(diào)用其他方法、使用常量、注入環(huán)境變量等 |
將 @Configuration 與 @ConfigurationProperties 結(jié)合使用,并綁定到 application.yml,是 Spring Boot 實(shí)現(xiàn)“外部化配置 + 類型安全注入”的核心模式
假設(shè)你想讓驗(yàn)證碼的寬度、高度、字符集等可配置,而不是硬編碼在 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();
// 嵌套類:對(duì)應(yīng) 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; }
}
// 嵌套類:對(duì)應(yīng) 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()));
// 創(chuàng)建并配置 Kaptcha
Config config = new Config(properties);
DefaultKaptcha kaptcha = new DefaultKaptcha();
kaptcha.setConfig(config);
return kaptcha;
}
}
- @EnableConfigurationProperties(KaptchaProperties.class):告訴 Spring “請(qǐng)加載這個(gè)配置屬性類”
- captchaProducer(KaptchaProperties props):Spring 自動(dòng)注入已綁定好值的 KaptchaProperties 實(shí)例
- 所有配置來自 application.yml,無需硬編碼
public class KaptchaProperties 這個(gè)類 怎么沒用yml的配置?
KaptchaProperties 這個(gè)類 本身不會(huì)自動(dòng)讀取 application.yml,它只是一個(gè)“空殼”——必須配合 SpringBoot 的機(jī)制(如 @EnableConfigurationProperties 或 @Component +@ConfigurationPropertiesScan)才能真正綁定 YAML 配置。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- SpringBoot 使用 @Configuration 集中管理 Bean的實(shí)戰(zhàn)步驟
- Springboot關(guān)于@Configuration的用法解讀
- 將SpringBoot屬性配置類@ConfigurationProperties注冊(cè)為Bean的操作方法
- SpringBoot中@AutoConfiguration和@Configuration區(qū)別
- SpringBoot @ConfigurationProperties + Validation實(shí)現(xiàn)啟動(dòng)期校驗(yàn)解決方案
- springboot使用@ConfigurationProperties實(shí)現(xiàn)自動(dòng)綁定配置參數(shù)屬性
- SpringBoot中@Configuration和@Bean和@Component相同點(diǎn)詳解
相關(guān)文章
SpringBoot實(shí)現(xiàn)快遞物流查詢功能(快遞鳥)
本文將基于springboot2.4.0實(shí)現(xiàn)快遞物流查詢,物流信息的獲取通過快遞鳥第三方實(shí)現(xiàn),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-10-10
Java8接口默認(rèn)靜態(tài)方法及重復(fù)注解原理解析
這篇文章主要介紹了Java8接口默認(rèn)靜態(tài)方法及重復(fù)注解原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
synchronized底層原理之JVM層面的鎖實(shí)現(xiàn)細(xì)節(jié)與流程
本文從JVM底層視角,詳細(xì)拆解了synchronized的實(shí)現(xiàn)邏輯,涵蓋鎖的存儲(chǔ)載體(對(duì)象頭的MarkWord)、鎖的觸發(fā)指令(monitorenter/monitorexit指令和ACC_SYNCHRONIZED標(biāo)志位)以及鎖的調(diào)度機(jī)制,感興趣的朋友跟隨小編一起看看吧2026-01-01
Java反射的應(yīng)用之動(dòng)態(tài)代理深入理解
這篇文章主要介紹了Java反射的應(yīng)用之動(dòng)態(tài)代理深入理解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
java動(dòng)態(tài)添加外部jar包到classpath的實(shí)例詳解
這篇文章主要介紹了java動(dòng)態(tài)添加外部jar包到classpath的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09

