SpringBoot通过Map实现天然的策略模式

在Spring框架中,自动装配(Auto-wiring)是Spring容器自动将对象注入到其他对象中,以减少手动配置的需求。当你使用Map<String, T>类型的依赖时,Spring提供了几种特殊的方式来自动装配这些Map类型的bean

1. 为什么能"自动收集"所有子类

复制代码
  @Autowired
  private Map<String, OssLogic> ossLogicMap;

这是 Spring 的一个内置特性:当注入目标类型为 Map<String, T> 时,Spring 会把容器中所有的 T 类型(及其子类)Bean 全部收集进这个 Map,key 是 bean 名称,value 是对应的 Bean 实例。

所以这里并不需要手动一个个注册。只要某个类满足:

  • 是 OssLogic / BaseLogic 的子类(或本身)
  • 被 Spring 管理为 Bean(项目里用 @Configuration 标注,等价于 @Component)

例如 BjlhOssLogic extends OssLogic(@Configuration),它们都会被自动装进对应的 Map。

2. bean 名称的命名约定

bean 名称由类名首字母小写得到,例如:

  • BjlhOssLogic → beanName = bjlhOssLogic

init() 启动时按命名约定从 beanName 反推 vendorCode

3.运行时如何分发

注册完成后,OssLogic自身注入了 OssVendorRegistry,通过 vendorCode 查表找到对应处理器,找不到则回退到通用逻辑:

复制代码
  public String getRealCalling(String calling, String callType, String oldCalling, String vendorCode) {
    OssLogic handler = vendorRegistry.findOssLogic(vendorCode);
    if (handler != null) {
      return handler.getRealCalling(calling, callType, oldCalling);
    }
    log.debug("运营商 {} 无专门号码标准化处理逻辑,使用原始号码", vendorCode);
    return calling;

新增一个运营商的处理逻辑时,只需新建一个继承 OssLogic的类,用 @Configuration 标注,且类名遵循 {vendorCode}OssLogic 约定即可,无需修改任何注册代码,Spring 启动时会自动把它收进 Map,init() 自动完成注册。

完整代码

复制代码
import lombok.extern.slf4j.Slf4j;
import net.icsoc.ark.api.common.oss.detail.OssLogic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

/**
 * OSS 运营商注册中心,利用 Spring Map 自动注入收集所有 OssLogic 子类 Bean。
 * <p>
 * 核心机制:
 * <ul>
 *   <li>通过 {@code Map<String, OssLogic>} 自动注入所有子类</li>
 *   <li>按命名约定 {@code {vendorCode}OssLogic 从 beanName 提取 vendorCode</li>
 *   <li>特殊 vendorCode(含 - 等字符)通过別名映射处理</li>
 *   <li>未找到对应的处理器时返回 null,调用方使用通用规则回退</li>
 * </ul>
 *
 * @author hudeyong
 */
@Component
@Slf4j
public class OssVendorRegistry {

  @Autowired
  private Map<String, OssLogic> ossLogicMap;

  private final Map<String, OssLogic> vendorOssLogicCache = new HashMap<>();

  @PostConstruct
  public void init() {
    // 注册 OssLogic 映射
    if (ossLogicMap != null) {
      for (Map.Entry<String, OssLogic> entry : ossLogicMap.entrySet()) {
        String beanName = entry.getKey();
        // beanName 格式如 "bjlhOssLogic",去掉 "OssLogic" 后缀得到 vendorCode
        String vendorCode = beanName.replace("OssLogic", "");
        vendorOssLogicCache.put(vendorCode, entry.getValue());
        log.info("注册 OssLogic: {} -> {}", vendorCode, entry.getValue().getClass().getSimpleName());
      }
    }
  }

  /**
   * 根据 vendorCode 查找 OssLogic
   *
   * @param vendorCode 运营商代码
   * @return 对应的 OssLogic,找不到返回 null
   */
  public OssLogic findOssLogic(String vendorCode) {
    return vendorOssLogicCache.get(vendorCode);
  }
}
相关推荐
0x532 小时前
网站通信(一)
java
To_OC2 小时前
Next.js + Redis 构建笔记系统:Redis Hash 实战与性能优化
redis·后端·next.js
Terra.K2 小时前
Java异常学习[特殊字符]
java·开发语言·学习
葡萄城技术团队4 小时前
InfluxDB 2\.x 深度解析:核心架构、Flux 函数与制造业落地指南(三)
java·开发语言·架构
Super 含4 小时前
Android 启动优化(五):线程、GC 与 IO 为什么会拖慢启动?
java·服务器·数据库
counting money4 小时前
Java IO流详解:从InputStream到文件操作实战
java·开发语言·python
程序员小八7775 小时前
上海百度B端java后端日常实习一面
java·开发语言
北斗落凡尘5 小时前
LangGraph 入门实战(11)--输出模式
后端·python·langchain
demo007x6 小时前
Hermes-Agent 技术架构
前端·后端·agent
mldong6 小时前
零依赖的秘密:8 大 SPI 设计
java·架构