告别 if-else!Spring Boot 动态切换实现类的 N 种姿势(全网最全)
·
告别 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
最简单、代码最少、可扩展性最强!
九、企业级最佳实践
- 一个接口 + 多个实现
- 实现类提供 getType() 或指定 beanName
- 用 Map 注入,一行代码匹配
- 新增业务只加类,不改老代码(完美符合开闭原则)
- 完全告别 if-else!
总结
- Spring Boot 天生支持动态切换实现类,根本不用写 if-else
- 最优方案:
@Autowired Map<String, 接口>直接匹配 - 所有方案都遵循开闭原则,易扩展、易维护
- 从业务系统到中间件,都能通用
更多推荐




所有评论(0)