【SpringBoot】applicationContext.getBeansOfType(class)获取某一接口所有实现类,应用于策略模式

一、问题的提出

在实际工作中,我们经常会遇到一个接口及多个实现类的情况,并且在不同的条件下会使用不同的实现类。

二、应用场景

springboot 项目中通过 ApplicationContext.getBeansOfType(class) 获取某一接口的所有实现类,并通过枚举完成策略模式,替代 if/else,使代码更加优雅易于拓展。

三、ApplicationContext.getBeansOfType(class) 介绍

java 复制代码
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> var1) throws BeansException;

从上面的源码上我们可以看出来这个方法能返回一个接口的全部实现类(前提是所有实现类都必须由 Spring IoC 容器管理

java 复制代码
        Map<String, TrafficModeService> map = applicationContext.getBeansOfType(TrafficModeService.class);

从上面的代码上(下面案例中工厂类有) ,Map 中的 String 的值是各个实现类的名称 busModeServiceImpl、trainModeServiceImpl(首字母小写),Map 中的 value 是各个 key 对应的策略实现类

四、案例 demo

假设从 A 点到 B 点有多种交通方式,每种交通方式的费用不同,可以根据乘客的需要进行选择。按照该需求,设计如下:

有一个交通方式的接口,接口有两个方式,一个查询费用、一个查询该交通方式的类型,同时,我们可以用一个枚举类型类标识交通类型。

我们还需要一个工厂类来根据交通类型标识查找该交通类型的 Bean 实例,从而使用该实例,获得交通类型的详细信息及该交通类型的操作。

1、TrafficCodeEmun 枚举制定接口信息

java 复制代码
@AllArgsConstructor
public enum TrafficCodeEmun {

    TRAIN("TRAIN","火车"),
    BUS("BUS","大巴"),

    ;

    private final String code;
    private final String desc;
}

2、TrafficModeFactory 工厂类获取接口实现 bean,并存储到 ConcurrentHashMap,通过枚举获取对应的实现 bean

java 复制代码
@Component
@Slf4j
public class TrafficModeFactory implements ApplicationContextAware {

    public static final ConcurrentHashMap<TrafficCodeEmun, TrafficModeService> TRAFFIC_BEAN_MAP = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("TrafficModeFactory 启动开始");
        Map<String, TrafficModeService> map = applicationContext.getBeansOfType(TrafficModeService.class);

        map.forEach((key, value) -> TRAFFIC_BEAN_MAP.put(value.getCode(), value));
        log.info("TrafficModeFactory 启动完成");
    }

    public static <T extends TrafficModeService> T getTrafficMode(TrafficCodeEmun code) {
        return (T) TRAFFIC_BEAN_MAP.get(code);
      }

}

3、定义策略接口 TrafficModeService

java 复制代码
public interface TrafficModeService {

    /**
     * 查询交通方式编码
     * @return 编码
     */
    TrafficCodeEmun getCode();
     

    /**
     * 查询交通方式的费用,单位:分
     * @return 费用
     */
    Integer getFee();

}

4、策略实现类 BusModeServiceImpl、TrainModeServiceImpl

java 复制代码
@Service
public class TrainModeServiceImpl implements TrafficModeService {

    /**
     * 查询交通方式编码
     * @return 编码
     */
    @Override
    public TrafficCodeEmun getCode() {
        return TrafficCodeEmun.TRAIN;
    }

    /**
     * 查询交通方式的费用,单位:分
     * @return 费用
     */
    @Override
    public Integer getFee() {
        return 5000;
    }

}

5、定义 controller

java 复制代码
    @PostMapping("/test3")
    public Integer test3() {
        Integer fee = TrafficModeFactory.getTrafficMode(TrafficCodeEmun.TRAIN).getFee();
        return fee;
    }

6、启动项目,访问 localhost:8080/testUtils/test3 测试即可看到对应接口返回

java 复制代码
5000

五、总结

  • 一个策略接口被多个策略实现类所实现,具体使用哪一种根据用户选择的类型来和 Map 里的 key 做匹配,获取对应的实现来调用具体的策略方法。
  • 使用 ConcurrentHashMap ,而不使用 HashMap ,是 put 的时候,键和值都不能为空,防止 key 对应的实现类没有注入进去,导致空指针的问题。

六、参考文档

使用Spring的getBeansOfType实现接口多实现类的动态调用

applicationContext.getBeansOfType(class)获取某一接口的所有实现类,应用于策略模式简单demo

相关推荐
码智社33 分钟前
Java实现RSA密钥生成、加密解密、加签验签
java
wear工程师42 分钟前
ThreadLocal 在线程池里为什么会串数据:别只会答内存泄漏
java·后端
Iruoyaoxh42 分钟前
栈和队列~
java·开发语言
审小匠OpenCPAi1 小时前
银行流水核查怎么自动化?单边匹配、双向勾稽与图聚类异常检测的工程对比
java·前端·人工智能·python·审计
码上上班1 小时前
docker课程
java·docker·容器
腻害兔1 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:CRM 客户关系模块深度解析——从线索到回款,一套完整的 B2B 销售闭环是怎么搭的?
java·前端·javascript·vue.js·产品经理·ai编程
whyfail1 小时前
前端学 Spring Boot(2):一次点击,如何穿过整个后端?
前端·spring boot·后端
乔伊酱1 小时前
我被列表查询折磨了 7 年,直到有一天我发现它不是 ORM 的事!
spring boot·graphql
达子6662 小时前
第9章_HarmonyOs图解 用Java开发UI
java·ui·harmonyos
龙虾PRO3 小时前
能源与股票量化核心差异,AI全链路落地实操手册
java·面试·职场和发展