手动实现一个RPC框架
前言
RPC = Remote Procedure Call,远程调用服务协议
RPC跟HTTP服务协议有什么区别可以看看https://blog.csdn.net/wangyunpeng0319/article/details/78651998 ,文章里说的很好也很清楚,总结来说,RPC服务效率肯定高于HTTP,一般用于分布式服务系统中,但是HTTP使用起来肯定复杂度是低于RPC框架的。
提示:以下是本篇文章正文内容,下面案例可供参考
一、RPC服务的远程调用过程
作为一个开发者,平时HTTP服务我们会经常用到,比如一个服务A提供了一个查询接口API,另外一个服务B需要去调用这个API接口,那么如果用RPC实现的话,就需要两个服务有共同约定好的接口,然后服务A去实现这个接口,服务B去调用
二、具体代码实现
1.模块
代码如下(示例):
package com.rpc.study.demo.localclient;
import com.rpc.study.demo.UserApi;
import com.rpc.study.demo.server.User;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class LocalMain {
//本地调用远程服务
public static void main(String args[]){
UserApi userApi = (UserApi) rpc(UserApi.class);
User user= userApi.selectById(1);
System.out.println("本地输出远程调用结果:\n"+user.toString());
}
public static Object rpc(final Class clazz){
// Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
return Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz},new InvocationHandler() {
/*
* @param proxy 代理对象
* @param method 代理的方法对象
* @param args 方法调用时参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket=new Socket("127.0.0.1",8888);
String className=clazz.getName();
String methodName=method.getName();
Class<?>[] parameterTypes=method.getParameterTypes();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeUTF(className);
objectOutputStream.writeUTF(methodName);
objectOutputStream.writeObject(parameterTypes);
objectOutputStream.writeObject(args);
ObjectInputStream objectInputStream=new ObjectInputStream(socket.getInputStream());
Object o=objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();
return o;
}
});
}
}
package com.rpc.study.demo.server;
import com.rpc.study.demo.UserApi;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerMain {
public static void main(String[] args) {
try {
ServerSocket serverSocket=new ServerSocket(8888);
System.out.println("启动远程服务监听...");
//监听客户端发来消息
while (true){
Socket socket=serverSocket.accept();
ObjectInputStream objectInputStream=new ObjectInputStream(socket.getInputStream());
//读取客户端传输协议包
String className=objectInputStream.readUTF();
String methodName=objectInputStream.readUTF();
Class<?>[] parameterTypes=(Class<?>[])objectInputStream.readObject();
Object[] arguments= (Object[]) objectInputStream.readObject();
Class clazz=null;
//服务注册:API到具体实现的映射
if(className.equals(UserApi.class.getName())){
clazz=UserService.class;
}
//传入方法名,方法参数类型获得方法对象
Method method=clazz.getMethod(methodName,parameterTypes);
//传入实现类对象,方法参数数组,方法对象执行获得返回结果对象
Object result=method.invoke(clazz.newInstance(),arguments);
ObjectOutputStream objectOutputStream=new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
objectInputStream.close();
objectOutputStream.close();
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.rpc.study.demo.server;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String username;
private String message;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", message='" + message + '\'' +
'}';
}
}
package com.rpc.study.demo.server;
import com.rpc.study.demo.UserApi;
public class UserService implements UserApi {
@Override
public User selectById(Integer id) {
User user=new User();
user.setUsername("张三");
user.setId(id);
user.setMessage("张三是胖子");
System.out.println("UserService调用了selectById()方法查询用户.....");
return user;
}
}
package com.rpc.study.demo;
import com.rpc.study.demo.server.User;
public interface UserApi {
User selectById(Integer id);
}