RPC 框架有很多可扩展的地方,如:序列化类型、压缩类型、负载均衡类型、注册中心类型等等。
假设框架提供的注册中心只有zookeeper
,但是使用者想用Eureka
,修改框架以支持使用者的需求显然不是好的做法。
最好的做法就是留下扩展点,让使用者可以不需要修改框架,就能自己去实现扩展。
JDK 原生已经为我们提供了 SPI 机制,ccx-rpc
在此基础上,进行了性能优化和功能增强。
在讲解 ccx-rpc
的增强 SPI 之前,先来了解一下 JDK SPI
吧。
讲解的 RPC 框架叫
ccx-rpc
,代码已经开源。
Github:https://github.com/chenchuxin/ccx-rpc
Gitee:https://gitee.com/imccx/ccx-rpc
JDK SPI
下面我们来看一下 JDK SPI 是如何使用的。
我们先来定义一个序列化接口和 JSON
、Protostuff
两种实现:
public interface Serializer {
byte[] serialize(Object object);
}
public class JSONSerializer implements Serializer {
@Override
public byte[] serialize(Object object) {
return JSONUtil.toJsonStr(object).getBytes();
}
}
public class ProtostuffSerializer implements Serializer {
private static final LinkedBuffer BUFFER = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
@Override
public byte[] serialize(Object object) {
Schema schema = RuntimeSchema.getSchema(object.getClass());
return ProtostuffIOUtil.toByteArray(object, schema, BUFFER);
}
}
在 resources/META-INF/services
目录下添加一个 com.xxx.Serializer
的文件,这是 JDK SPI
的配置文件:
com.xxx.JSONSerializer
com.xxx.ProtostuffSerializer
如何使用 SPI 将实现类加载出来呢?
public static void main(String[] args) {
ServiceLoader<Serializer> serviceLoader = ServiceLoader.load(Serializer.class);
Iterator<Serializer> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
Serializer serializer= iterator.next();
System.out.println(serializer.getClass().getName());
}
}
输出如下:
com.xxx.JSONSerializer
com.xxx.ProtostuffSerializer
通过上面的例子,我们可以了解到 SPI 的简单用法。接下来,我们就来看增强版的 SPI 是如何实现的,又增强在哪里。
增强版 SPI
我们先来看看增强版 SPI 是如何使用的吧,还是拿序列化来举例。
- 定义接口,接口加上
@SPI
注解
@SPI
public interface Serializer {
byte[] serialize(Object object);
}