目录
一、介绍
本片文章将实现请求响应同步,什么是请求响应同步呢?就是当我们发起一个请求时,希望能够在一定时间内同步(线程阻塞)等待响应结果。
我们通过netty实现rpc调用时,由于客户端和服务端保持连接,在此期间客户端会有无数的接口调用(并发),而此时,每次发送的请求需要能够及时响应获取调用结果,服务端一次次返回调用结果,客户端在处理响应结果时,需要与请求建立联系,确保每一次的请求能够正确获取到对应的调用结果。
由于在一个应用中,客户端与服务端的channel只有一条,所有线程都通过该channel进行rpc调用,所以,在接下来客户端设计中,每个线程发送的请求将会分配一个id,当请求发送完毕之后,该线程会进行阻塞状态,等待channel收到请求id对应返回的响应消息时唤醒或超时唤醒。在接下来服务端设计中,服务端收到客户端的rpc调用请求,对该请求进行处理,将该请求的id和处理结果写入响应类中进行返回。

二、依赖引入
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.101.Final</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.8.0</version>
</dependency
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
</dependencies>
三、公共部分实现
1、结构

2、Message类,所有Request和Response类的父类,最关键的字段就是messageType,子类继承之后进行赋值,该值与类的类型进行绑定,用于byte字节数组反序列化时能够获取到需要反序列化的类型。
@Data
public abstract class Message {
protected Byte messageType;
}
RpcRequest,用于客户端向服务端发起调用的消息通信类
@Data
@ToString
public class RpcRequest extends Message{
private String id;
private String param;
public RpcRequest() {
this.id = UUID.randomUUID().toString();
super.messageType = MessageConstant.rpcRequest;
}
}
RpcResponse,用于服务端向客户端返回结构的消息通信类
@Data
@ToString
public class RpcResponse extends Message{
private String id;
private String result;
public RpcResponse() {
super.messageType = MessageConstant.rpcResponse;
}
}
3、MessageConstant,通过数值常量messageType绑定消息类型,在序列化对象时,会在数据中记录对象的messageType,在反序列化对象时,会从数据包中拿到messageType,将其转化为对应的消息类型进行处理
public class MessageConstant {
public final static Byte rpcRequest = 1;
public final static Byte rpcResponse = 2;
public static Map<Byte, Class<? extends Message>> messageTypeMap = new ConcurrentHashMap<>();
static {
messageTypeMap.put(rpcRequest, RpcRequest.class);
messageTypeMap.put(rpcResponse, RpcResponse.class);
}
public static Class<? extends Message> getMessageClass(Byte messageType){
return messageTypeMap.get(messageType);
}
}
4、序列化工具,用于将类对象序列化为字节数组,以及将字节数组反序列化为对象
public class SerializationUtil {
private final static Map<Class<?>, Schema<?>> schemaCache = new ConcurrentHashMap<>();
/**
* 序列化
*/
public static <T> byte[] serialize(T object){
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Class<T> cls = (Class<T>) object.getClass();
Schema<T> schema = getSchema(cls);
return ProtostuffIOUtil.toByteArray(object, schema, buffer);
} catch (Exception e) {
throw e;
} finally {

本文详细介绍了如何使用Netty和protobuf实现请求响应同步的RPC调用,涉及公共部分的Message类设计、序列化工具、Server端的请求处理、Client端的同步等待策略以及半包黏包的解决方案。
最低0.47元/天 解锁文章
4311

被折叠的 条评论
为什么被折叠?



