本节commit源码地址:ca82236
盗一张Guide哥的图哈
我们首先要思考,RPC框架的原理:原理其实很简单,客户端和服务端都可以访问到通用的接口,但是只有服务端有这个接口的实现类,客户端调用这个接口的方式,是通过网络传输,告诉服务端我要调用这个接口,服务端收到之后找到这个接口的实现类,并且执行,将执行的结果返回给客户端,客户端拿到返回的结果,结束。
我们先进行最基本的实现,然后一步一步完善,假设我们现在知道服务端的地址,尝试来实现一下这个过程。
定义接口
public interface HelloService {
String hello(HelloObject object);
}
hello方法需要传递一个对象,HelloObject对象,注意这个对象需要实现Serializable
接口,因为它需要在调用过程中从客户端传递给服务端,必须进行序列化。
//自动加上所有属性的get set toString hashCode equals方法
@Data
//添加一个含有所有已声明字段属性参数的构造函数
@AllArgsConstructor
public class HelloObject implements Serializable {
//Serializable序列化接口没有任何方法或者字段,只是用于标识可序列化的语义。
//实现了Serializable接口的类可以被ObjectOutputStream转换为字节流。
//同时也可以通过ObjectInputStream再将其解析为对象。
//序列化是指把对象转换为字节序列的过程;反序列化则是把持久化的字节文件数据恢复为对象的过程。
private Integer id;
private String message;
}
接着我们在服务端对这个接口进行实现,实现的方式也很简单,返回一个字符串就行。
public class HelloServiceImpl implements HelloService {
/**
* 使用HelloServiceImpl初始化日志对象,方便在日志输出的时候,可以打印出日志信息所属的类。
*/
private static final Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class);
@Override
public String hello(HelloObject object) {
//使用{}可以直接将getMessage()内容输出
logger.info("接收到:{}", object.getMessage());
return "这是调用的返回值:id=" + object.getId();
}
}
就是在客户端和服务端之间的传输的数据规定一个固定格式,具体采用什么格式,可以考虑服务端需要哪些信息,才能唯一确定服务端需要调用哪个接口的哪个方法呢?
首先,肯定要知道接口的名字和方法的名字,但是由于方法重载的缘故,我们还需要这个方法的所有参数的类型,最后,服务端处理时,还需要参数的实际值,那么服务端知道以上四个条件,就可以找到这个方法并且调用处理了。我们把这四个条件写到一个对象里,到时候传输时传输这个对象就行了。即RpcRequest
对象
@Data
//使用创建者模式,一次性给所有变量初始赋值
@Builder
public class RpcRequest implements Serializable {
/**
* 待调用接口名称
*/
private String interfaceName;
/**
* 待调用方法名称
*/
private String methodName;
/**
* 待调用方法的参数
*/
private Object[] parameters;
/**
* 待调用方法的参数类型
*/
private Class>[] paramTypes;
}
服务器调用完这个方法后,需要给客户端返回哪些信息呢?如果调用成功的话,显然需要返回值,如果调用失败了,就需要失败的信息,这里封装一个RpcResponse
对象作为返回
@Data
public class RpcResponse implements Serializable {
/**
*响应状态码
*/
private Integer statusCode;
/**
*响应状态码对应的信息
*/
private String message;
/**
*成功时的响应数据
*/
private T data;
/**
* @description 成功时服务端返回的对象
* @param [data]
* @return [com.panda.rpc.entity.RpcResponse]
* @date [2021-02-03 17:31]
*/
public static RpcResponse success(T data){
RpcResponse response = new RpcResponse<>();
response.setStatusCode(ResponseCode.SUCCESS.getCode());
response.setData(data);
return response;
}
/**
* @description 失败时服务端返回的对象
* @param [code]
* @return [com.panda.rpc.entity.RpcResponse]
* @date [2021-02-03 17:42]
*/
public static RpcResponse fail(ResponseCode code){
RpcResponse response = new RpcResponse<>();
response.setStatusCode(code.getCode());
response.setMessage(code.getMessage());
return response;
}
}
响应状态码ResponseCode对象定义
@AllArgsConstructor
@Getter
public enum ResponseCode {
SUCCESS(200,"调用方法成功"),
FAIL(500,"调用方法失败"),
NOT_FOUND_METHOD(501,"未找到指定方法"),
NOT_FOUND_CLASS(502,"未找到指定类");
private final int code;
private final String message;
}
本节结束……