专栏首页微观技术借助SPI 解决复杂业务扩展问题

借助SPI 解决复杂业务扩展问题

首先我们了解下何为SPI,SPI全称:Service Provider Interface,由一方提供接口规范,另一方负责具体实现。其理念跟软件设计模式中的策略模式有点类似,前者是业务架构设计维度,后者是接口编程维度。

SPI优势:有效解决了代码高耦合问题,避免使用大量的if else 嵌套逻辑,大大提高了系统的可维护性和扩展性。对于复杂的业务场景,可以实现系统间的解耦,通过Restful接口完成交互,又避免了不同的商户接入带来的重复开发工作。

JDK原生用法

通过规则约定加规范的方式,按照接口名称定义配置文件,并将处理不同业务逻辑的实例类添加到配置文件中,通过类加载器完成加载。

/**
 * 创建订单接口
 * @author onlyone
 */
public interface OrderService {
    String createOrder(AddOrderParam addOrderParam);
}

然后在 “META-INF/services”路径下创建文件 “com.boot.service.OrderService”,文件内容为:

com.boot.service.impl.TaobaoOrderService
com.boot.service.impl.TianmaoOrderService

最后借助jdk原生的ServiceLoader去META-INF/services目录下加载配置文件并将类实例化,完成调用。

代码示例:

https://github.com/aalansehaiyang/spi-example

Dubbo 框架用法

jdk原生框架采用全部加载机制,不管需不需要。导致系统初始启动时会占用大量系统资源,耗时较长。dubbo对其进行改造,重写加载机制,采用按需加载。

  • 自定义注解 @SPI
  • 重写加载类ExtensionLoader
  • 并大量使用缓存,提升性能
  • 提供getExtension方法,可以获取具体实现类
 public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
   ....各种校验
    } else {
        //缓存中获取扩展加载器,为空则进行新建
        ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
            loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
}
public T getExtension(String name) {    
   。。。参数校验   
    Holder<Object> holder = cachedInstances.get(name); //从缓存中获取持有者
    if (holder == null) { //如果为空,创建一个持有者
        cachedInstances.putIfAbsent(name, new Holder<Object>());
        holder = cachedInstances.get(name);
    }
    Object instance = holder.get(); //从持有者获取实现类
    if (instance == null) { //如果为空
        synchronized (holder) {
            instance = holder.get();
            //双重判空检查
            if (instance == null) { 
                //采用懒加载模式加载实现类
                instance = createExtension(name);
                holder.set(instance);
            }
        }
    }
    return (T) instance;
}

架构衍生

随着一个企业越做越大,沉淀了很多数据,会通过API开放形式接入网关,给外部的ISV提供原始数据服务,进一步打造业务生态圈。但是这种模式有个缺点,规范和实现由内部控制,外部单向依赖。

如果某些业务场景需要双向依赖,可以考虑使用SPI模式,由平台方定义接口规范,第三方来实现内部逻辑,通过HTTP协议来调用。可以理解成SPI是传统API的反向调用。

存在这样一种业务场景,平台需要向开发者请求数据信息。比如一些大电商卖家都有自己的仓库,本地库存系统,自己的售卖网站,同时也在淘宝、京东、拼多多等三方平台售卖商品,如果想共享一套库存数据要怎么设计,可以考虑SPI。

图引自程序架道

首先平台方定义业务场景,并在场景下定义SPI接口规范,接入方按规范实现接口逻辑(比如:调用本地数据库判断是否有库存),并将API服务注册到网关。当用户访问平台系统时,会根据访问的店铺、IP地址、用户数据等信息,路由寻址到指定的商户系统,完成数据交互,并进行后续业务流程。

当然,不同公司的技术实力参差不齐,系统稳定性、接口响应速度都不一样,平台系统的容错能力、超时机制要深入建设,避免局部慢请求,引发雪崩效应。

小结:

  • 提供了内部数据的开放能力,借助ISV的开发能力,形成一个大的业务生态圈
  • 外部系统数据可以以插件的形式注册到平台,由平台指定统一规范和路由能力, 满足更复杂的业务诉求。

本文分享自微信公众号 - 微观技术(weiguanjishu),作者:TomGE

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ​Proxy系统架构升级

    爬虫是个高风险行业,如果操作不当,很容易造成“攻击”假象,给数据源技术部门带来很多麻烦。另外随着大家的安全意识逐步提高,风控标准也越来越严。为了避免身份被识别,...

    用户7676729
  • 面试中数据库事务的几个关键点

    事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一...

    用户7676729
  • 如何打造一个高效的研发团队

    互联网公司的成功很大一部分归结为人才储备,如何打造有活力、持续创新的研发团队,相信很多管理者都比较关心。

    用户7676729
  • 关于CLR内存管理一些深层次的讨论[上篇]

    半年之前,PM让我在部门内部进行一次关于“内存泄露”的专题分享,我为此准备了一份PPT。今天无意中将其翻出来,觉得里面提到的关于CLR下关于内存管理部分的内存还...

    蒋金楠
  • 原 适配iPhoneX

    作者:汪娇娇 时间:2017年12月26日 我这里说的适配iPhoneX,是一种比较简单粗暴的适配法,就是填满整个屏幕(包括安全区域和上下左右这些边,见下图)。...

    jojo
  • Django实战-信息资讯-Form 表单注册

    Django网络应用开发的5项基础核心技术包括模型(Model)的设计,URL的设计与配置,View(视图)的编写,Template(模板)的设计和Form(表...

    小团子
  • Python花式编程案例集锦(7):判断回文

    所谓回文,是指一个词或一句话,正着读和反着读都一样,例如eye,did之类的单词。 参考代码: ? 运行结果: ?

    Python小屋屋主
  • API网关Ocelot 使用Polly 处理部分失败问题

    在实现API Gateway过程中,另外一个需要考虑的问题就是部分失败。这个问题发生在分布式系统中当一个服务调用另外一个服务超时或者不可用的情况。API Gat...

    张善友
  • Python接口开发实现步骤详解

    砸漏
  • Internet Explorer 安装指定版本浏览器方法,ie的降级和升级

    首先你需要知道指定版本的补丁。比如 11.0.145 是 KB4516045。如果你要的版本低就卸载补丁。如果要的版本高就安装新的补丁。

    小蓝枣

扫码关注云+社区

领取腾讯云代金券