什么是RPC框架?
- RPC:remote procedure call 即:远程过程调用
- 在分布式架构中离不开服务之间的通信
- 为了提高服务之间通信的性能:产生了如Dubbo、webservice、Thrift等RPC框架
简易版RPC框架实现
- 通过实现一个简易版本的RPC框架,去学习其原理
- 首先我们创建需要一个服务端
服务端实现
- rpc-server:以quickstart的方式快速创建一个maven工程
- 以同样的方式创建rpc-server-api和rpc-server-provider
- 创建api和provider模块的作用是在本机模拟服务之间的调用
- rpc-server-api:定义客户端需要拿到的一些信息,如接口、传输对象等打成jar包作为依赖使用
- rpc-server-provider:服务提供方基于api的实现,提供服务供客户端进行调用。
- 至此我们的服务端基础架构就搭建完成了
API实现
- 写一个简单的接口
public interface UserService {
String handToUser(String content);
String saveUser(User user);
}
Provider实现
- 依赖api(需要把api打成jar包到本地仓库)
<dependency>
<groupId>com.self.struggle</groupId>
<artifactId>rpc-server-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 服务简单实现
public class UserServiceImpl implements UserService {
@Override
public String handToUser(String s) {
return "hi,"+s+".Welcome come!";
}
@Override
public String saveUser(User user) {
return user.toString();
}
}
- 我们的服务端实现是要提供给客户端调用的,所以我们需要暴露出我们的服务实现
- 提供服务暴露的方法—使用代理的形式暴露服务(基于socket实现)
public class RpcServerProxy {
/** 线程池回顾
* newCached:可缓存地线程池,核心线程数为0,最大线程数为 Integer.MAX_VALUE
* 在回收时间内,可以对创建好地线程进行复用
*/
ExecutorService executorService = Executors.newCachedThreadPool();
public void publish(int port) {
ServerSocket serverSocket = null;
try {
// port:通过端口暴露服务
serverSocket = new ServerSocket(port);
// 不断地接受请求
while (true) {
// 建立socket连接:通过ois oos去处理 accept:阻塞
Socket socket = serverSocket.accept();
// 利用线程池来处理请求 每一个socket交给一个DealRequest:具体地处理逻辑
executorService.execute(new DealRequest(socket));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- DealRequest实现
public class DealRequest implements Runnable {
private Socket socket;
public DealRequest(Socket socket) {
this.socket = socket;
}
/**
* 处理socket连接中地流信息
*/
@Override
public void run() {
ObjectInputStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
// 获取客户端发送请求中地输入流
objectInputStream = new ObjectInputStream(socket.getInputStream());
/* 输入流包含的内容
* 请求的目标类,方法名称,参数 在 api 中定义一个对象,接收返回信息
*/
// 反序列化过程
RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();
// 通过反射 实现调用
Object result = invoke(rpcRequest);
// 写入结果
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(objectInputStream != null) {
try {
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(objectOutputStream != null) {
try {
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private Object invoke(RpcRequest request) throws Exception {
// 反射调用
Object[] params = request.getParams();
Class<?>[] types = new Class[params.length];
for (int i = 0; i < params.length; i++) {
types[i] = params[i].getClass();
}
Class<?> clazz = Class.forName(request.getClassName());
Object obj = clazz.newInstance();
Method method = clazz.getMethod(request.getMethodName(), types);
return method.invoke(obj, params);
}
}
发布服务
- 在App.java中发布服务
public class App
{
public static void main( String[] args )
{
RpcServerProxy rpcServerProxy = new RpcServerProxy();
rpcServerProxy.publish(8080);
}
}
- 至此,简易版的服务端实现完成
客户端实现
- 客户端需要去调用服务端
- 通过远程代理服务调用
代理服务实现
- 通过反射的方式进行调用,具体实现在 RemoteInvocationHandler 中
public class RpcClientProxy {
public Object clientProxy(final Class<?> interfaceCls, final String host, final int port) {
return Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class<?>[]{interfaceCls}, new RemoteInvocationHandler(host, port));
}
}
- RemoteInvocationHandler
- 在invoke方法中构建传输对象,由RpcNetTransport发送请求
public class RemoteInvocationHandler implements InvocationHandler {
private String host;
private int port;
public RemoteInvocationHandler(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RpcRequest rpcRequest = new RpcRequest();
rpcRequest.setClassName(method.getDeclaringClass().getName());
rpcRequest.setMethodName(method.getName());
rpcRequest.setParams(args);
// 远程通信
RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
return rpcNetTransport.send(rpcRequest);
}
}
- RpcNetTransport
public class RpcNetTransport {
private String host;
private int port;
public RpcNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
public Object send(RpcRequest request) {
Socket socket = null;
Object result = null;
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
try {
// 建立连接
socket = new Socket(host, port);
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(request);
objectOutputStream.flush();
objectInputStream = new ObjectInputStream(socket.getInputStream());
result = objectInputStream.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
服务调用
public class App
{
public static void main( String[] args )
{
UserService userService = (UserService) new RpcClientProxy().clientProxy(UserService.class, "localhost", 8080);
String status = userService.handToUser("你好");
System.out.println("server back:"+status);
}
}
验证结果
-
客户端
-
服务端
流程图
- nexus代表私服仓库
- ProxyClient:客户端代理,socket建立连接后,通过动态代理的方式进行远程调用
- provider:业务逻辑实现,对api进行处理
- RpcproxyServer:服务端代理,暴露服务,供客户端调用
源码和升级版本
- https://gitee.com/joyful_live/rpc.git