Spring SPI

2023-11-27 16:11:23 浏览数 (2)

本文将通过Spring SPI的案例,给大家介绍如何设计一个简单但又强大的SPI扩展机制。

SPI(Service Provider Interface)是一种常用的扩展机制,它通过不改变原有系统的情况下,允许添加新的功能模块。Spring就是利用SPI实现了许多可配置和可替换的设计,比如动态代理,资源加载等功能通过SPI进行扩展。

我们以一个简单的RPC调用接口作为案例,来展示Spring中的SPI设计思路:

代码语言:java复制
public interface RpcCall {

  Object call(String url, String method, Object[] args);

}

这个RpcCall接口定义了远程调用的常规操作,我们来看看如何通过SPI来实现不同协议(如HTTP、TCP等)的调用扩展:

代码语言:java复制
// RpcCall的默认实现
public class DefaultRpcCall implements RpcCall {

  @Override
  public Object call(String url, String method, Object[] args) {
    // 具体调用实现  
  }

}

定义一个默认实现类,这是SPI不可或缺的一部分。我们通过环境变量配置使用哪个实现:

代码语言:java复制
String implementation = 
  System.getenv("rpc.implementation");

RpcCall call;
if(implementation == null){
  call = new DefaultRpcCall();
}else{
  call = loadImplementation(); 
}

//方法调用
call.call("http://localhost:8080","hello",new Object[] {});

loadImplementation方法负责通过反射或其他方式加载配置的实现类:

代码语言:java复制
private RpcCall loadImplementation(){

  try{
     Class clazz = Class.forName(implementation);
     return (RpcCall) clazz.getDeclaredConstructor().newInstance();
  }catch(Exception e){
    return new DefaultRpcCall();
  }

}

接下来,我们可以很容易地实现HTTP和TCP两种调用协议:

代码语言:java复制
// HTTP 实现
public class HttpRpcCall implements RpcCall{

  @Override
  public Object call(String url, String method, Object[] args){
    // HTTP 实现代码 
  }

}


// TCP 实现  
public class TcpRpcCall implements RpcCall{

  @Override
  public Object call(String url, String method, Object[] args){
   // TCP 实现代码
  }

}

通过设置环境变量"rpc.implementation=com.demo.HttpRpcCall"或"rpc.implementation=com.demo.TcpRpcCall",我们就可以一键切换调用实现而无须修改任何调用代码。

这个架构同样适用于Spring中许多组件的扩展,例如AuthorizationManager、HandlerMethodArgumentResolver等。我们可以通过配置文件或代码方式很方便地切换实现类。

与服务提供者模型(Service Provider Model)相比,SPI能更好地支持热插拔和零配置。开发者也无需修改调用代码就可以扩展新的功能。这给系统架构带来了很好的灵活性。

所以,在设计可扩展组件时,使用SPI提供的接口和默认实现可以帮助我们快速搭建出一个“开放-关闭”和“可配置”的系统框架。这也是Spring之所以如此流行的一个重要原因。

总结来说:

  1. 定义一个标准接口和一个默认实现作为SPI的基础
  2. 通过配置从 SPI 中动态加载完整的实现类
  3. 实现类实例通过接口进行调用操作
  4. 实现无侵入性的拓展能力

当然,SPI还有一些缺点,比如行为不一致、难以升级等。但对于需要动态扩展能力的系统来说,它提供了一种非常简单实用的解决方案。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞