RPC介绍
RPC,Remote Procedure Call 即远程过程调用,远程过程调用其实对标的是本地过程调用
一个RPC框架要进行使用应该要具有如下的组件(功能)
从整体层次来看,一个RPC协议的框架应该具有三个层面:
- 服务的注册中心
- 请求服务的客户端
- 提供服务的服务端。
关于这三个层面,其实细分的话,又可以分为以下几个部分,每一部分完成各自的任务。
1.客户端(客户端发起请求,调用远程方法)
2.客户端存根(存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端)作为一个代理类
3.网络传输 通过网络传输,把我们调用的远程接口中的参数传输给服务端,这样服务端的接口实现类才能进行处理,在处理完成之后,还要通过网络传输的方式把返回的结果发送回来。网络传输一般有原生的Soket方式,还有现在常用的Netty
4.服务端存根( 接收客户端发送过来的请求消息并进行解析,然后再调用服务端的方法进行处理)作为一个代理类
5.服务端 (提供服务的一方,有远程接口和实现类)
简易RPC实现
通用接口
Service接口:
public interface HelloService {
String hello(HelloObject object);
}
传输数据的实体类(在网络传输的过程中,实体类都需要实现Serializable接口,代表可序列化):
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HelloObject implements Serializable {
private Integer id;
private String message;
}
Service接口的实现类:
@Service
public class HelloServiceImpl implements HelloService {
private static final Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class);
@Override
public String hello(HelloObject object) {
logger.info("接收到消息:{}", object.getMessage());
return "这是Impl1方法";
}
}
传输格式
RpcRequest对象:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RpcRequest implements Serializable {
/**
* 请求号
*/
private String requestId;
/**
* 待调用接口名称
*/
private String interfaceName;
/**
* 待调用方法名称
*/
private String methodName;
/**
* 调用方法的参数
*/
private Object[] parameters;
/**
* 调用方法的参数类型
*/
private Class<?>[] paramTypes;
/**
* 是否是心跳包
*/
private Boolean heartBeat;
}
RpcResponse对象:
@Data
@NoArgsConstructor
public class RpcResponse<T> implements Serializable {
/**
* 响应对应的请求号
*/
private String requestId;
/**
* 响应状态码
*/
private Integer statusCode;
/**
* 响应状态补充信息
*/
private String message;
/**
* 响应数据
*/
private T data;
public static <T> RpcResponse<T> success(T data, String requestId) {
RpcResponse<T> response = new RpcResponse<>();
response.setRequestId(requestId);
response.setStatusCode(ResponseCode.SUCCESS.getCode());
response.setData(data);
return response;
}
public static <T> RpcResponse<T> fail(ResponseCode code, String requestId) {
RpcResponse<T> response = new RpcResponse<>();
response.setRequestId(requestId);
response.setStatusCode(code.getCode());
response.setMessage(code.getMessage());
return response;
}
}
状态枚举类:
@AllArgsConstructor
@Getter
public enum ResponseCode {
SUCCESS(200, "调用方法成功"),
FAIL(500, "调用方法失败"),
METHOD_NOT_FOUND(500, "未找到指定方法"),
CLASS_NOT_FOUND(500, "未找到指定类");
private final int code;
private final String message;
}
客户端实现(动态代理)
客户端方面,由于在客户端这一侧我们并没有接口的具体实现类,就没有办法直接生成实例对象。这时,我们可以通过动态代理的方式生成实例,并且调用方法时生成需要的RpcRequest对象并且发送给服务端