😊 @ 作者: 一恍過去
💖 @ 主頁: https://blog.csdn.net/zhuocailing3390
🎊 @ 社區: Java技術棧交流
🎉 @ 主題: SpringBoot通過Map實現天然的策略模式
?? @ 創作時間: 2025年03月25日
目錄
- 前言
- 底層機制解析
- Spring的集合類型自動裝配
- @Resource注解的行為
- 實現原理
- 使用
- 直接使用Map<String,T>
- 指定Map中的bean類型
- 定義策略接口
- 定義實現類
- 策略使用
- 驗證
- 自定義注解實現
前言
策略模式是一種行為設計模式,它允許在運行時選擇算法的行為。在Spring框架中,我們可以利用@Resource
注解和Map
集合來優雅地實現策略模式。
在Spring框架中,當你使用@Resource
注解注入一個Map<String, T>
時,Spring會自動將所有類型為T的bean收集到這個Map中,其中:
- Key是bean的名稱
- Value是bean實例
底層機制解析
Spring的集合類型自動裝配
Spring框架對集合類型的依賴注入有特殊處理:
- 當注入List時,會收集所有類型為T的bean
- 當注入Map<String, T>時,會收集所有類型為T的bean,并以bean名稱作為key
@Resource注解的行為
@Resource
注解默認按名稱裝配,但當目標是一個Map時,Spring會特殊處理:
- 如果Map的key是String類型,value是某個接口/類
- Spring會查找所有實現該接口/繼承該類的bean
- 將這些bean以"bean名稱->bean實例"的形式放入Map
實現原理
Spring在依賴注入時的處理流程:
- 發現字段/方法參數是Map<String, T>類型
- 在應用上下文中查找所有類型為T的bean
- 創建一個新的Map實例
- 遍歷找到的所有bean,以bean名稱作為key,bean實例作為value放入Map
- 將這個Map注入到目標字段/參數中
使用
直接使用Map<String,T>
我們直接定義一個Controller,并且在Controller中使用@Resource
和Map<String,T>
@RestController
@RequestMapping("/test")
public class TestController {@Resourceprivate Map<String, Object> beanMap = new ConcurrentHashMap<>();public void beanMap() {System.out.println(beanMap.size());}
}
驗證:
可以看到map中存了項目中所有的bean對象
指定Map中的bean類型
在實際的開發中,我們希望Map中只是存儲需要的Bean,并且Controller中可以根據beanName進行轉發到不同的Service中,步驟如下:
定義策略接口
public interface PaymentStrategy {void pay();
}
定義實現類
@Service("ALI")@Slf4jpublic class AliStrategyService implements PaymentStrategy {@Overridepublic void pay() {log.info("使用支付寶支付");}}@Service("WX")@Slf4jpublic class WxStrategyService implements PaymentStrategy {@Overridepublic void pay() {log.info("使用微信支付");}}
策略使用
@RestController
@RequestMapping("/test")
public class TestController {@Resourceprivate Map<String, PaymentStrategy> beanMap = new ConcurrentHashMap<>();public void beanMap() {PaymentStrategy wx = beanMap.get("WX");wx.pay();PaymentStrategy ali = beanMap.get("ALI");ali.pay();}
}
驗證
可以看到map中,就只有兩個Bean,并且key就是我們通過@Service(value)定義的名稱
自定義注解實現
- 自定義一個注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface PaymentType {String value();
}
- 注解替換:將原有的
@Service(value)
替換為@PaymentType (value)
,比如:
@PaymentType("CARD")
@Slf4j
public class CardStrategyService implements PaymentStrategy {@Overridepublic void pay() {log.info("使用銀行卡支付");}
}
- **意義:**可以更好表示策略模式,讓其他開發人員一眼可以看出
當前的Service
使用了策略模式