告别 if-else!Spring Boot 动态切换实现类的 N 种姿势(全网最全)

你是不是还在写大量if-else/switch来动态选择实现类?
比如:支付方式(微信/支付宝/云闪付)、消息推送(微信/短信/邮件)、文件存储(本地/OSS/MinIO)……

Spring Boot 原生就支持 N 种零 if-else 动态切换实现类的方案,优雅、解耦、可扩展,新增业务直接加类,不用改老代码!

本篇一次性给你整理最实用、企业级落地的 6 种姿势,从简单到高级全覆盖!


一、先看痛点(你肯定写过)

// 垃圾代码:大量 if-else,新增逻辑必须改这里,违反开闭原则
public PayResult pay(String type, BigDecimal amount){
    if("wxpay".equals(type)){
        return new WxPayService().pay(amount);
    }else if("alipay".equals(type)){
        return new AliPayService().pay(amount);
    }else if("unionpay".equals(type)){
        return new UnionPayService().pay(amount);
    }
    throw new RuntimeException("不支持的支付方式");
}

目标:
去掉所有 if-else,通过类型自动匹配实现类


二、姿势 1:@Autowired + List / Map(最简单,推荐 90% 场景)

Spring 自动注入所有实现类,零配置,最简单,企业最常用!

1. 定义接口

public interface PayService {
    // 标识:用来匹配类型
    String getType();
    PayResult pay(BigDecimal amount);
}

2. 编写实现类(每个实现类声明自己的类型)

@Service
public class WxPayService implements PayService {
    @Override
    public String getType() { return "wxpay"; }
    
    @Override
    public PayResult pay(BigDecimal amount) {
        return new PayResult("微信支付成功");
    }
}

@Service
public class AliPayService implements PayService {
    @Override
    public String getType() { return "alipay"; }
    
    @Override
    public PayResult pay(BigDecimal amount) {
        return new PayResult("支付宝支付成功");
    }
}

3. 动态注入 + 匹配(无 if-else)

@Service
public class PayServiceImpl {

    // 关键:Spring 自动注入所有 PayService 的实现类
    @Autowired
    private List<PayService> payServiceList;

    public PayResult pay(String type, BigDecimal amount) {
        // 直接匹配,零 if-else
        PayService payService = payServiceList.stream()
                .filter(service -> service.getType().equals(type))
                .findFirst()
                .orElseThrow(() -> new RuntimeException("不支持的支付方式"));
                
        return payService.pay(amount);
    }
}

升级版:直接用 Map(性能更高)

@Autowired
private Map<String, PayService> payServiceMap;

public PayResult pay(String type, BigDecimal amount) {
    PayService payService = payServiceMap.get(type);
    if(payService == null) throw new RuntimeException("不支持的支付方式");
    return payService.pay(amount);
}

Spring 会自动把 beanName 作为 key,实现类作为 value。
你只需要给实现类指定 beanName = type 即可!


三、姿势 2:@Qualifier 手动指定注入(静态切换)

适合启动时确定、运行时不变的场景,比如环境切换(dev/prod)。

@Service
public class PayService {

    @Autowired
    @Qualifier("wxPayService") // 直接指定实现类
    private PayService payService;
}

缺点:运行时无法切换,适合固定场景。


四、姿势 3:策略模式 + 工厂类(经典解耦)

标准策略模式,结构清晰,适合复杂业务。

1. 工厂类

@Component
public class PayFactory {

    @Autowired
    private Map<String, PayService> payServiceMap;

    public PayService getInstance(String type){
        PayService service = payServiceMap.get(type);
        if(service == null) throw new RuntimeException("类型错误");
        return service;
    }
}

2. 使用

@Service
public class PayServiceImpl {
    @Autowired
    private PayFactory payFactory;

    public PayResult pay(String type, BigDecimal amount){
        PayService payService = payFactory.getInstance(type);
        return payService.pay(amount);
    }
}

优点:职责清晰,工厂统一管理。


五、姿势 4:@Conditional 条件注入(按条件自动激活)

适合按配置、环境、参数自动选择实现类

示例:配置文件指定 pay.type=wxpay,自动注入对应实现类。

@Service
@ConditionalOnProperty(name = "pay.type", havingValue = "wxpay")
public class WxPayService implements PayService {}

@Service
@ConditionalOnProperty(name = "pay.type", havingValue = "alipay")
public class AliPayService implements PayService {}

优点

  • 完全无感知切换
  • 配置改一改,实现类自动换

六、姿势 5:lookup-method 动态获取 Bean(高级)

适合多例 Bean / 每次都要新对象的场景。

public abstract class PayService {
    @Lookup
    public abstract PayService getPayService(String type);
}

Spring 自动实现方法,根据 name 获取 Bean。

适合:需要频繁创建实例的场景


七、姿势 6:Spring SPI 扩展(最优雅,可插拔)

Spring 官方标准插件化架构,新增实现类完全不用修改原有代码!

1. resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

com.xxx.service.WxPayService
com.xxx.service.AliPayService

2. 使用

SpringFactoriesLoader.loadFactories(PayService.class, getClass().getClassLoader());

优点

  • 彻底解耦
  • 可插拔、可模块化
  • 框架级别的方案

八、6 种姿势怎么选?(直接照抄)

方案 复杂度 适用场景 推荐度
@Autowired + List/Map 绝大多数业务(支付、消息、存储) ⭐⭐⭐⭐⭐
策略工厂 ⭐⭐ 复杂业务,需要统一管理 ⭐⭐⭐⭐
@Conditional ⭐⭐ 按环境/配置自动切换 ⭐⭐⭐
@Qualifier 固定不变的实现 ⭐⭐
@Lookup ⭐⭐⭐ 多例 Bean、需要每次新建 ⭐⭐
Spring SPI ⭐⭐⭐⭐ 插件化、模块化、框架扩展 ⭐⭐⭐⭐

终极推荐:

90% 的业务直接用:@Autowired + Map/List
最简单、代码最少、可扩展性最强!


九、企业级最佳实践

  1. 一个接口 + 多个实现
  2. 实现类提供 getType() 或指定 beanName
  3. Map 注入,一行代码匹配
  4. 新增业务只加类,不改老代码(完美符合开闭原则)
  5. 完全告别 if-else!

总结

  1. Spring Boot 天生支持动态切换实现类,根本不用写 if-else
  2. 最优方案@Autowired Map<String, 接口> 直接匹配
  3. 所有方案都遵循开闭原则,易扩展、易维护
  4. 从业务系统到中间件,都能通用
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐