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);
  }
}
相关推荐
喵个咪6 分钟前
GoWind Admin|风行 — 开箱即用的企业级全栈中后台框架:六类审计日志与等保合规
后端·安全·go
CallFay云起未来17 分钟前
AI客服上线后多久才能回本?从TCO到ROI的完整测算方法
java·大数据·人工智能·架构·文心一言
Sam_Deep_Thinking17 分钟前
什么是CountDownLatch?
java·后端·面试·程序员
小蒜学长23 分钟前
基于SpringBoot和Vue的低卡食品销售系统的设计与实现(代码+数据库+LW)
java·后端·springboot·健康管理·低卡食品销售系统
CRMEB系统商城27 分钟前
前后端技术栈全面换代!CRMEB 多商户(Java)v3.0更新预告
java·开发语言·小程序·php
白起那么早28 分钟前
idea 插件-把数据库的表画出来
数据库·后端·intellij idea
蓝宝石的傻话33 分钟前
onvif-go(mickeyzzc/onvif-go v2)完整参考手册:从建工程到写出自己的 NVR 接入
开发语言·后端·golang
喵个咪33 分钟前
GoWind Admin|风行 — 开箱即用的企业级全栈中后台框架:AI 模块
后端·go·ai编程
喵个咪35 分钟前
GoWind Admin|风行 — 开箱即用的企业级全栈中后台框架:AK/SK 机器凭证
后端·安全·架构
Sayai1 小时前
Neo4j 内嵌模式(Embedded)实战:Java 嵌入式 vs 服务端部署的写入性能对比与 GC 调优
java·开发语言·性能优化·neo4j·图数据库