视频教程地址 DT课堂(原名颜群)
整体思路
RPC(Remote Procedure Call),即远程过程调用。使用RPC,可以像使用本地的程序一样使用远程计算机上的程序。RPC使得开发分布式程序更加容易。下面是一个基于java的简单的RPC实例,有助于学习dubbo或grpc等框架的原理。
原理分析
RPC采用客户机/服务器模式。请求程序就是客户端,而服务提供程序就是服务端。也就是说需要两个角色,服务端和客户端。首先,客户端调用进程发送一个调用信息(调用的接口,方法名,方法传入参数等)给服务端,然后等待应答信息。在服务器端,当一个调用信息到达,服务器获得调用信息并解析执行调用的接口和方法,然后发送调用的方法返回值,然后等待下一个调用信息,最后,客户端接收到服务端发送回来的方法返回信息。
以下是代码
服务端
首先需要业务类,然后需要一个注册中心,注册中心可以把被调用的业务类注册到一个map集合中,然后根据客户端发送过来的调用信息执行相应的业务类对象的方法,并返回方法的返回值
创建需要发布的业务类接口和具体实现类
1 2 3 4 5 6 7 | package org.rpc.service; public interface HelloService { Object sayHello(String name); } |
1 2 3 4 5 6 7 8 9 10 11 | package org.rpc.service; public class HelloServiceImpl implements HelloService { public Object sayHello(String name) { // TODO Auto-generated method stub return "hello," +name; } } |
然后是服务端的主体类,就是注册中心。定义三个方法start()初始化方法,stop()停止服务方法,register()注册中心
package org.rpc.service; public interface Server { void start(); void stop(); void register(Class service,Class serviceImpl); }
具体实现类,首先声明一个map集合来来存放业务类,key是业务类的接口名,value是接口对应的具体实现类class对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | package org.rpc.service; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ServerCenter implements Server { private static HashMap<String, Class> serviceRegister= new HashMap<>(); private static int PORT= 0 ; //根据本地计算机性能生成对应容量的线程池 private static ExecutorService servicePool= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public ServerCenter() { } public ServerCenter( int port) { this .PORT=port; } @Override public void start() { ServerSocket server= null ; try { server= new ServerSocket(); server.bind( new InetSocketAddress(PORT)); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } while ( true ) { System.out.println( "等待客户端连接..." ); Socket socket = null ; try { //服务器等待连接,每当有客户端连接就开启线程执行调用信息处理类 socket = server.accept(); servicePool.execute( new ServiceTask(socket)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override public void stop() { servicePool.shutdown(); } @Override public void register(Class service, Class serviceImpl) { serviceRegister.put(service.getName(), serviceImpl); } //具体调用信息处理类,解析客户端发来的调用信息并执行对应的业务方法并相应方法的返回值 private class ServiceTask implements Runnable{ private Socket socket= null ; public ServiceTask() { } public ServiceTask(Socket socket) { this .socket = socket; } @Override public void run() { ObjectInputStream ois= null ; ObjectOutputStream oos= null ; try { System.out.println( "客户端已连接" ); ois= new ObjectInputStream(socket.getInputStream()); //获取客户端发来的接口名 String className=ois.readUTF(); //获取客户端发来的方法 String methodName=ois.readUTF(); //获取客户端发来的方法参数类型 Class[] methodTypes=(Class[]) ois.readObject(); //获取客户端发来的方法参数值 Object[] args =(Object[]) ois.readObject(); //从map中找到需要的接口并执行客户端调用的方法 Class service=serviceRegister.get(className); Method method = service.getMethod(methodName,methodTypes); Object returns = method.invoke(service.newInstance(), args); oos= new ObjectOutputStream(socket.getOutputStream()); //返回方法执行的结果 oos.writeObject(returns); } catch (Exception e) { e.printStackTrace(); } finally { try { //关闭资源 if (oos!= null )oos.close(); if (ois!= null )ois.close(); if (socket!= null )socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } |
客户端
客户端使用动态代理来接受服务端的业务类返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | package org.rpc.client; import java.io.IOException; 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.InetSocketAddress; import java.net.Socket; public class Client { @SuppressWarnings ( "unchecked" ) public static <T> T getRemoteProxyObj(Class serviceInterface,InetSocketAddress addr) { return (T)Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class<?>[] {serviceInterface}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args){ Socket socket = null ; ObjectInputStream ois= null ; ObjectOutputStream oos= null ; Object result= null ; try { socket= new Socket(); socket.connect(addr); oos= new ObjectOutputStream(socket.getOutputStream()); //发送需要的接口名 oos.writeUTF(serviceInterface.getName()); //发送需要的方法名 oos.writeUTF(method.getName()); //方法参数类型 oos.writeObject(method.getParameterTypes()); //方法参数 oos.writeObject(args); ois= new ObjectInputStream(socket.getInputStream()); result=ois.readObject(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (oos!= null )oos.close(); if (ois!= null )ois.close(); if (socket!= null )socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return result; } }); } } |
测试
服务端使用register()方法对HelloService类进行注册并开启服务等待客户端连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package org.rpc.test; import org.rpc.service.HelloService; import org.rpc.service.HelloServiceImpl; import org.rpc.service.Server; import org.rpc.service.ServerCenter; public class ServerTest { public static void main(String[] args) { new Thread( new Runnable() { @Override public void run() { Server server = new ServerCenter( 9999 ); server.register(HelloService. class , HelloServiceImpl. class ); server.start(); } }).start(); } } |
客户端直接声明需要调用的业务类的接口接受动态代理对象并执行需要的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package org.rpc.test; import java.net.InetSocketAddress; import org.rpc.client.Client; import org.rpc.service.HelloService; public class ClientTest { public static void main(String[] args) throws ClassNotFoundException { HelloService hs=Client.getRemoteProxyObj(Class.forName( "org.rpc.service.HelloService" ), new InetSocketAddress( "127.0.0.1" , 9999 )); System.out.println(hs.sayHello( "world" )); } } |
视频教程地址http://aibd.ke.qq.com
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现