• 如何优雅的实现接口统一调用


    耦合问题

    有些时候我们在进行接口调用的时候,比如说一个push推送接口,有可能会涉及到不同渠道的推送,以我目前业务场景为例,我做结算后端服务的,会与金蝶财务系统进行交互,那么我结算后端会涉及到多个结算单类型,如果每一个种类型的结算单都去暴露一个contoller接口给前端提供,而且其实对接第三方的接口,有些接口是共通的;

    前端涉及到的问题
    • 需要调用后端多个controller,不同接口不同的传参数,如果遇到后端接口修改,会涉及到多个页面的修改,耦合度很高;
    • 需要对多个按钮设置权限配置;

    后端涉及到的问题

    • 需要每个业务接口,都去写一个对接第三方接口的push推送方法,无形中增加很多重复的代码,耦合度也很高;
    • 如果涉及到第三方服务接口改造,后端接口也需要进行更改,会修改大量代码;

    如何解决

    1. 创建对接第三方服务的微服务,站定为tps服务,该服务只作为一个后端微服务,与第三方服务进行对接,并且合理封装调用参数,将公共参数提出进行封装;
    2. 后端其余业务系统对接这个独立的微服务,比如订单、结算、供应商系统对接这个服务,由tps服务统一提供对接接口,其余服务实现这个tps提供的feign接口;
    3. 业务系统只需要关注service层业务的实现,无需处理对接的业务逻辑;

    大致的流程图就是这样的

    具体实现

    Tps服务

    Tps服务暴露feign接口,前端统一通过Tps提供的接口进行调用

    1. //对接第三方服务接口
    2. public interface IKingdeeManagementService {
    3. Boolean push(KingdeePushCO.Request request);
    4. }

    Feign接口实现类

    1. @Slf4j
    2. @Service
    3. public class KingdeeManagementServiceImpl implements IKingdeeManagementService {
    4. @Autowired
    5. private ApplicationContext applicationContext;
    6. @Autowired
    7. private KingdeeThirdSettingService kingdeeThirdSettingService;
    8. @Override
    9. public Boolean push(KingdeePushCO.Request request) {
    10. KingdeeBusinessPushServiceEnum kingdeePushServiceEnum = KingdeeBusinessPushServiceEnum.getKingdeePushServiceEnumByType(request.getBusinessType());
    11. IKingdeeBusinessPushService kingdeePushService = null;
    12. try {
    13. kingdeePushService = (IKingdeeBusinessPushService) applicationContext.getBean(kingdeePushServiceEnum.getClazz());
    14. } catch (BeansException e) {
    15. log.error("当前类型暂未实现,请联系开发");
    16. throw new ServiceException("当前类型暂未实现,请联系开发");
    17. }
    18. R result = null;
    19. result = kingdeePushService.pushKingdee(request);
    20. return true;
    21. // }
    22. }
    23. }

    枚举类定义

    1. public enum KingdeeBusinessPushServiceEnum {
    2. private Class clazz;
    3. private Integer type;
    4. private String interFaceName;
    5. KingdeeBusinessPushServiceEnum(Class clazz, Integer type, String interFaceName) {
    6. this.clazz = clazz;
    7. this.type = type;
    8. this.interFaceName =interFaceName;
    9. }
    10. RECEIPT_VOUCHER(IJaKingdeeBillClient.class,KingdeeBusinessTypeConstant.RECEIPT_VOUCHER, KingdeeSettingEnum.INTERFACE_TYPE_JA_RECEIPT_VOUCHER.getCode()),
    11. ;
    12. }

    分别有clazz、type、interFaceName属性,

    • clazz定义为feign接口,业务系统提供的服务接口;
    • type前端需要传的参数,不同的Integer值代表,不同的feign接口映射;
    • interFaceName第三方接口枚举,表示需要具体调哪个第三方接口;

    业务系统

    拿bms服务举例说明: 继承Tps服务的feign接口,重写push方法;

    A6B39528-1238-457A-9AC2-B48BBD209B5E.png

    Feign接口实现,通过factory工厂类初始化,不同的service实现类;

    925352EC-D5A7-4995-A07B-AB59EC22AA35.png

    JaKingdeeFactoryUtil 工厂工具类,获取工厂实例,这里其实也可以使用枚举映射,避免以后接口太多,需要写很多case when;

    4D53151E-44CA-4B51-9C63-9E7C5FB6D991.png

    JaKingdeeServiceFactory是个接口,提供方法;

    15F12B49-72AE-49FC-9F3D-7A3E3A8956B1.png

    实现上面的接口,通过单例工厂的模式double check的模式实现,并且加悲观锁,避免一个工作线程多次创建工厂实例,SpringContextUtils./getBean/获取servcie实例,业务层只需要实现service接口,实现不同业务逻辑的push推送方法;

    0D2D53C9-2E71-45E5-B1EE-555B61732BBF.png

    总结

    这是我之前设计的关于接口统一调用的流程,当然其实还是包括对接第三方重复调用的问题、调用结果缓存、调用超时解决、失败降级的一些策略,如果还有更好的接口统一调用方式欢迎大家评论区留言讨论;

  • 相关阅读:
    Java中的数组
    Stream强化
    万数藏:国内首家影视IP艺术数藏平台今日上线
    Python爬虫:selenium动态加载HTML的常用方法【汇总笔记】
    Spring Cloud Ribbon面试题大全
    Spring(一)Spring配置、构造注入、bean作用域、bean自动装配
    Redis数据类型——list类型数据的扩展操作
    Java swing(GUI) mysql实现的进销存管理系统源码+运行教程+文档
    发烧友实测 | OKA40i-C开发板SATA硬盘挂载及读写速率测试
    YOLOv8+swin_transfomerv2
  • 原文地址:https://blog.csdn.net/weixin_48890074/article/details/133857421