RPC是什么?
RPC(Remote Procedure Call)即远程过程调用,是一种计算机通信协议,它允许程序在不同的计算机之间进行通信和交互,就像本地调用一样。
在单机后台中,调用方法很简单,但是在分布式系统中,服务器A上的程序要想调用服务器B上提供的方法,就需要用到RPC。RPC 允许一个程序(称为服务消费者)像调用自己程序的方法一样,调用另一个程序(称为服务提供者)的接口,而不需要了解数据的传输处理过程、底层网络通信的细节等。这些都会由 RPC 框架帮你完成,使得开发者可以轻松调用远程服务,快速开发分布式系统。
如果没有RPC,A调用B上的方法,就需要发送HTTP请求,每个方法的调用都要写一个HTTP请求,会十分麻烦。而RPC的作用就是让程序员在使用分布式系统中的方法调用和单机系统的方法调用上感受不出区别。
RPC框架的实现思路
消费者调用提供者方的order方法,都需要什么呢?
- 提供者需要启动一个web服务,这样消费者方发送的HTTP请求才能被提供者接收到。
- 提供者怎么知道收到的请求是请求哪个方法呢?可以构造一个统一请求参数类,类中包括服务名称,方法名称等等。这样提供者收到请求后,从请求中解析出服务名称和方法名称,再通过反射的方式调用方法,得到结果并返回。这个解析请求,调用方法,返回结果的过程在请求处理器中进行。
- 由于Java对象无法直接在网络中传输,所以要对传输的参数进行序列化和反序列化。
- 基于代理模式,为消费者要调用的接口生成一个代理对象,由代理对象完成请求和响应的过程。
项目准备
在一个工程下创建几个Maven模块:
- example-common: 示例代码的公共依赖,包括接口,bean等
- example-consumer: 示例服务消费者代码
- example-provider: 示例服务提供者代码
- yu-rpc-easy: 简易版RPC框架
公共模块
用户实体类User:
public class User implements Serializable {
private String name;
}
接口UserService:
public interface UserService {
/**
* 获取用户
* @param user
* @return
*/
User getUser(User user);
}
服务消费者
EasyConsumerExample:
public class EasyConsumerExample {
public static void main(String[] args) {
// 获取UserService的代理对象
UserService userService = ServiceProxyFactory.getProxy(UserService.class);
User user = new User();
user.setName("yupi");
// 调用
User newUser = userService.getUser(user);
if(newUser != null){
System.out.println(newUser.getName());
}else{
System.out.println("user == null");
}
}
}
服务提供者
EasyProviderExample:
/**
* 简易服务提供者示例
*/
public class EasyProviderExample {
public static void main(String[] args) {
// 注册服务
LocalRegistry.register(UserService.class.getName(), UserServiceImpl.class);
// 提供服务
HttpServer httpServer = new VertxHttpServer();
// 开始web服务,监听6060端口
httpServer.doStart(6060);
}
}
UserServiceImpl:
/**
* 用户服务实现类
*/
public class UserServiceImpl implements UserService {
@Override
public User getUser(User user) {
System.out.println("用户名:" + user.getName());
return user;
}
}
RPC简易核心
- model: RpcRequest和RpcResponse是对请求参数和响应参数的封装
public class RpcRequest implements Serializable {
/**
* 服务名称
*/
private String serviceName;
/**
* 方法名称
*/
private String methodName;
/**
* 参数类型列表
*/
private Class<?>[] parameterTypes;
/**
* 参数列表
*/
private Object[] args;
}
/**
* RPC响应
*/
public class RpcResponse implements Serializable {
/**
* 响应数据
*/
private Object data;
/**
* 响应数据类型(预留)
*/
private Class<?> dataType;
/**
* 响应信息
*/
private String message;
/**
* 异常信息
*/
private Exception exception;
}
- proxy: 对接口服务的动态代理
/**
* 服务代理工厂(用于创建代理对象)
*/
public class ServiceProxyFactory {
public static <T> T getProxy(Class<T> serviceClass){
return (T) Proxy.newProxyInstance(
serviceClass.getClassLoader(),
new Class[]{serviceClass},
new ServiceProxy()
);
}
}
/**
* 服务代理(JDK动态代理)
*/
public class ServiceProxy implements InvocationHandler {
/**
* 调用代理
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 指定序列化器
Serializer serializer = new JdkSerializer();
// 构造请求
RpcRequest rpcRequest = RpcRequest.builder()
.serviceName(method.getDeclaringClass().getName())
.methodName(method.getName())
.parameterTypes(method.getParameterTypes())
.args(args)
.build();
try {
// 序列化
byte[] bodyBytes = serializer.serialize(rpcRequest);
// 发送请求
// todo 这里地址被硬编码了(需要使用注册中心和服务发现机制处理)
HttpResponse httpResponse = HttpRequest.post("http://localhost:6060")
.body(bodyBytes)
.execute();
byte[] result = httpResponse.bodyBytes();
// 反序列化
RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
return rpcResponse.getData();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- register: 本地服务注册器
/**
* 本地注册中心
*/
public class LocalRegistry {
/**
* 注册信息存储
*/
private static final Map<String, Class<?>> map = new ConcurrentHashMap<>();
/**
* 注册服务
* @param serviceName
* @param implClass
*/
public static void register(String serviceName, Class<?> implClass){
map.put(serviceName, implClass);
}
/**
* 获取服务
* @param serviceName
* @return
*/
public static Class<?> get(String serviceName){
return map.get(serviceName);
}
/**
* 删除服务
* @param serviceName
*/
public static void remove(String serviceName){
map.remove(serviceName);
}
}
- serializer: 序列化器
/**
* 序列化器接口
*/
public interface Serializer {
/**
* 序列化
* @param object
* @return
* @param <T>
* @throws IOException
*/
<T> byte[] serialize(T object) throws IOException;
/**
* 反序列化
* @param bytes
* @param type
* @return
* @param <T>
*/
<T> T deserialize(byte[] bytes, Class<T> type) throws IOException, ClassNotFoundException;
}
package com.yupi.yurpc.serializer;
import java.io.*;
/**
* JDK序列化器
*/
public class JdkSerializer implements Serializer{
@Override
public <T> byte[] serialize(T object) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.close();
return outputStream.toByteArray();
}
@Override
public <T> T deserialize(byte[] bytes, Class<T> type) throws IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
try {
return (T)objectInputStream.readObject();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
objectInputStream.close();
}
}
}
- server: web服务器
/**
* HTTP服务器接口
*/
public interface HttpServer {
/**
* 启动服务器
* @param port
*/
void doStart(int port);
}
public class VertxHttpServer implements HttpServer{
@Override
public void doStart(int port) {
// 创建Vert.x实例
Vertx vertx = Vertx.vertx();
// 创建HTTP服务器
io.vertx.core.http.HttpServer server = vertx.createHttpServer();
// 监听端口并处理请求
server.requestHandler(new HttpServerHandler());
// 启动HTTP服务器并监听指定端口
server.listen(port, result -> {
if(result.succeeded()){
System.out.println("Server is now listening on port");
}else{
System.out.println("Failed to start server: " + result.cause());
}
});
}
}
/**
* HTTP请求处理
*/
public class HttpServerHandler implements Handler<HttpServerRequest> {
@Override
public void handle(HttpServerRequest request) {
// 指定序列化器
final Serializer serializer = new JdkSerializer();
// 记录日志
System.out.println("Received request: " + request.method() + " " + request.uri());
// 异步处理HTTP请求
request.bodyHandler(body -> {
byte[] bytes = body.getBytes();
RpcRequest rpcRequest = null;
try {
rpcRequest = serializer.deserialize(bytes, RpcRequest.class);
}catch (Exception e){
e.printStackTrace();
}
// 构造响应结果对象
RpcResponse rpcResponse = new RpcResponse();
// 如果请求为null,直接返回
if(rpcRequest == null){
rpcResponse.setMessage("rpcRequest is null");
doResponse(request, rpcResponse, serializer);
return;
}
try {
// 获取要调用的服务实现类,通过反射调用
Class<?> implClass = LocalRegistry.get(rpcRequest.getServiceName());
Method method = implClass.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
Object result = method.invoke(implClass.newInstance(), rpcRequest.getArgs());
// 封装返回结果
rpcResponse.setData(result);
rpcResponse.setDataType(method.getReturnType());
rpcResponse.setMessage("ok");
} catch (Exception e) {
e.printStackTrace();
rpcResponse.setMessage(e.getMessage());
rpcResponse.setException(e);
}
// 响应
doResponse(request, rpcResponse, serializer);
});
}
/**
* 响应
* @param request
* @param rpcResponse
* @param serializer
*/
void doResponse(HttpServerRequest request, RpcResponse rpcResponse, Serializer serializer) {
HttpServerResponse httpServerResponse = request.response().putHeader("content-type", "application/json");
// 序列化
try {
byte[] serialized = serializer.serialize(rpcResponse);
httpServerResponse.end(Buffer.buffer(serialized));
} catch (IOException e) {
e.printStackTrace();
httpServerResponse.end(Buffer.buffer());
}
}
}