iT邦幫忙

2025 iThome 鐵人賽

DAY 13
0
Software Development

spring boot 3 學習筆記系列 第 13

Day13 - Spring Boot 另一種 Bean - 手動 Java 配置

  • 分享至 

  • xImage
  •  

前言:當我們無法修改原始碼時

Day12 內容中,我們學會了用 @Component@Service 等 Annotation,讓 Spring Boot 自動幫我們掃描並管理自己寫的類別。這種方式簡單又方便,適用於大多數專案程式碼。

但想像一個場景:

你買了一台現成的 咖啡機 (第三方類別, Third-party Library),這台機器是別人做好的,你不能在上面貼 @Component 的標籤。
但是,你還是希望城堡總管 (Spring IoC Container, 控制反轉容器) 能幫你管理它。

這時候該怎麼辦?我們就需要寫一份「操作說明書」,告訴總管該怎麼準備並管理這台機器。這份「說明書」就是 @Configuration + @Bean

介紹「食譜」組合技:@Configuration@Bean

當我們不能直接在食材 (類別) 上貼標籤時,就必須自己寫「食譜」,教 Spring 如何製作。

這組合包含兩個 Annotation:

  1. @Configuration => 一本食譜書,告訴 Spring:這裡專門定義要管理的 Bean。
  2. @Bean => 食譜裡的一道菜,告訴 Spring:這個方法會產生一個物件,請幫我管理起來。

@Configuration:這是一本 Bean 的食譜書

  • 加在 類別 (Class)
  • 這個類別專門用來定義 Bean 的建立方式
  • 本身不做事,但它會統整一堆「製作菜餚的方法」

@Bean:一道菜的具體作法

  • 加在 方法 (Method)
  • 該方法必須回傳一個物件
  • Spring 啟動時會執行這個方法,把回傳的物件放進 IoC 容器中,供全系統使用

命名規則:

  • 預設 Bean 的名字就是方法名稱。
  • 如果想自訂名稱,可以這樣寫:
@Bean(name = "eldenRingGame")
public Game myGame() {
    return new Game();
}

在使用的時候,可以搭配 @Qualifier("eldenRingGame") 指定要注入哪一個 Bean。

範例一:手動管理一個遊戲物件

1. 外部類別 (不能改它)

// 這個類別來自一個 .jar 檔,無法修改
public class Game {
    private String name = "艾爾登法環";

    public String play() {
        return "正在玩 " + name;
    }
}

說明:
這個 Game 類別代表的是我們無法直接修改的外部類別,可能來自第三方函式庫。我們不能在這個類別上加上 @Component 等註解 (Annotation),因為它的原始碼不在我們的控制範圍內。

2. 撰寫設定檔 (食譜書)

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.external.library.Game;

@Configuration // 一本食譜書
public class AppConfig {

    @Bean // 一道菜的製作方式
    public Game myGame() {
        return new Game(); // 只 new 一次,交給 Spring 管理
    }
}

說明:

  • @Configuration 告訴 Spring 這是一個專門用來配置 > Bean 的類別
  • myGame() 方法上的 @Bean 告訴 Spring:
    • 請執行這個方法一次
    • 將回傳的 Game 物件註冊為 Bean
    • Bean 的預設名稱就是 myGame
  • 應用程式啟動時,Spring 會自動執行這個方法,只 new 一次 Game 物件

3. 使用 Bean

package com.example.demo.controller;

import com.external.library.Game;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GameController {

    private final Game game;

    public GameController(Game game) {
        this.game = game;
    }

    @GetMapping("/play")
    public String playGame() {
        return game.play(); // 「正在玩 艾爾登法環」
    }
}

👉 我們沒有自己 new Game(),而是透過 Spring 取得。

說明:

  • 控制器 (Controller) 的建構子需要一個 Game 類別的參數
  • Spring 發現我們需要一個 Game 類型的 Bean,就會找到我們在 AppConfig 中定義的 myGame() 方法
  • 注入的 game 實例是由 Spring 容器管理的單一實例 (Singleton),整個應用程式中只會有這一個
  • 如果有多個相同類型的 Bean,可以使用 @Qualifier("myGame") 來指定要注入哪一個

手動配置 Bean 的運作流程

  1. Spring Boot 啟動,掃描到 @Configuration 類別
  2. 識別類別中所有標記 @Bean 的方法
  3. 執行這些方法並收集它們返回的物件
  4. 將這些物件註冊到 IoC 容器中,並以方法名稱作為 Bean 名稱
  5. 當其他元件(如控制器)需要這些物件時,Spring 從容器中提供它們

範例二:更真實的場景 - 配置 RestTemplate

RestTemplate 是 Spring 早期用來呼叫 API 的工具,常見的配置方式就是用 @Bean

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {

    @Bean
    public RestTemplate restTemplate() {
        // 未來可以在這裡加上更多客製化設定
        return new RestTemplate();
    }

    @Bean
    public Game myGame() {
        return new Game();
    }
}

在 Service 裡直接注入使用:

@Service
public class ApiService {

    private final RestTemplate restTemplate;

    public ApiService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String fetchDataFromApi() {
        String url = "https://api.example.com/data";
        return restTemplate.getForObject(url, String.class);
    }
}

流程圖:手動配置運作流程

應用程式啟動
       ↓
讀取 @Configuration 類別
       ↓
執行 @Bean 方法
       ↓
取得回傳的物件
       ↓
將物件註冊為 Bean 放入 IoC 容器
       ↓
需要時透過 @Autowired 或建構子注入

比較表:我該用 @Component 還是 @Bean

特性 @Component (及衍生 Annotation) @Bean
使用時機 我們自己專案中,可以控制的類別 來自外部函式庫、或需要複雜初始化邏輯的類別
宣告位置 類別 (Class) 上 方法 (Method) 上,且需在 @Configuration 類別中
控制權 Spring 幫我們建立物件 我們自己寫方法建立物件,再交給 Spring 管理
比喻 自動化貼標籤:「這個類別本身就是元件」 手寫食譜:「這個方法告訴你如何製作元件」

相關資料來源


上一篇
Day12 -Spring Boot 最常見的 Bean - 自動化元件掃描
下一篇
Day14 - Spring Boot 一切的起點 - 深入了解 @SpringBootApplication
系列文
spring boot 3 學習筆記16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言