Spring SPI

举报
赵KK日常技术记录 发表于 2023/11/27 16:10:49 2023/11/27
【摘要】 本文将通过Spring SPI的案例,给大家介绍如何设计一个简单但又强大的SPI扩展机制。SPI(Service Provider Interface)是一种常用的扩展机制,它通过不改变原有系统的情况下,允许添加新的功能模块。Spring就是利用SPI实现了许多可配置和可替换的设计,比如动态代理,资源加载等功能通过SPI进行扩展。我们以一个简单的RPC调用接口作为案例,来展示Spring中的...
本文将通过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还有一些缺点,比如行为不一致、难以升级等。但对于需要动态扩展能力的系统来说,它提供了一种非常简单实用的解决方案。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。