周围有很多同学入职后都在用RPC框架,在同学的介绍下,开始研究 我选择的是《分布式服务框架原理与实践》 李林锋著. 这本书 感兴趣的可以买来读一读。
目前看完最简单的RPC框架实现部分。下面是我在作者源码
RPC框架 说简单点就是 服务调用 分为远程服务提供者 远程服务发布者 和 本地服务代理
最简单的RPC框架 用到了 反射 对象流 动态代理 Socket 序列化和反序列化
首先是远程服务提供者 定义一个接口和一个实现方法
1 //服务端定义接口 2 public interface EchoService { 3 String echo(String ping); 4 } 5 //服务端接口的实现 6 public class EchoServiceImpl implements EchoService { 7 8 @Override 9 public String echo(String ping) { 10 // TODO Auto-generated method stub 11 return ping==null?"----> i am ojbk.":"i am ojbk"; 12 } 13 14 }
远程服务发布者
1 public class RpcExepoter { 2 //根据当前java application 获取线程池 3 static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 4 public static void exporter(String hostname,int port) throws Exception 5 { 6 ServerSocket server = new ServerSocket(); //服务端 7 server.bind(new InetSocketAddress(hostname, port));//监听客户端的Tcp连接 根据ip地址和端口号 8 try 9 { 10 while(true) 11 { 12 executor.execute(new ExepoterTask(server.accept()));//当接收到新的客户端连接之后 封装成Task 由线程池执行 13 } 14 } 15 finally 16 { 17 server.close(); 18 } 19 } 20 private static class ExepoterTask implements Runnable 21 { 22 Socket client = null; 23 public ExepoterTask(Socket client) { 24 this.client = client; 25 } 26 27 @Override 28 public void run() 29 { 30 ObjectInputStream input = null; 31 ObjectOutputStream output = null; 32 try 33 { 34 //将客户端发送的码流反序列化成对象 反射调用服务实现者 获取执行结果 35 input = new ObjectInputStream(client.getInputStream()); 36 String interfaceName = input.readUTF(); 37 Class<?> service = Class.forName(interfaceName); 38 String methodName = input.readUTF(); 39 Class<?>[] parameterTypes = (Class<?>[])input.readObject(); 40 Object[] arguments = (Object[])input.readObject(); 41 Method method = service.getMethod(methodName, parameterTypes); 42 Object result = method.invoke(service.newInstance(), arguments); 43 output = new ObjectOutputStream(client.getOutputStream()); 44 output.writeObject(result); 45 } 46 catch (Exception e) 47 { 48 e.printStackTrace(); 49 } 50 //远程调用结束之后 释放Socket等连接资源 防止句柄泄露 51 finally 52 { 53 if(output != null) 54 try { 55 output.close(); 56 }catch (IOException e2) { 57 e2.printStackTrace(); 58 } 59 if(input != null) 60 try { 61 input.close(); 62 }catch(IOException e) { 63 e.printStackTrace(); 64 } 65 if(client != null) 66 try { 67 client.close(); 68 }catch (Exception e2) { 69 e2.printStackTrace(); 70 } 71 } 72 } 73 } 74 }
1 //rpc客户端本地服务代理 2 public class RpcImporter<S> { 3 @SuppressWarnings("unchecked") 4 /** 5 * 6 * 7 * 8 * @param serviceClass 9 * @param addr 10 * @return 11 */ 12 public S importer(final Class<?> serviceClass,final InetSocketAddress addr) 13 { 14 //将本地的接口调用转换成jdk的动态代理,在动态代理中实现接口的远程调用 15 return (S) Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[] {serviceClass.getInterfaces()[0]}, new InvocationHandler() { 16 17 @Override 18 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 19 //创建Socket客户端,根据指定地址连接远程服务提供者 20 Socket socket = null; 21 ObjectOutputStream output = null; 22 ObjectInputStream input = null; 23 try { 24 socket = new Socket(); 25 socket.connect(addr); 26 output = new ObjectOutputStream(socket.getOutputStream()); 27 //将远程调用所需的接口类、方法名、参数列表等编码后发送给服务提供者。 28 output.writeUTF(serviceClass.getName()); 29 output.writeUTF(method.getName()); 30 output.writeObject(method.getParameterTypes()); 31 output.writeObject(args); 32 input = new ObjectInputStream(socket.getInputStream()); 33 return input.readObject(); 34 }finally { 35 if(socket != null) 36 socket.close(); 37 if(output != null) 38 output.close(); 39 if(input != null) 40 input.close(); 41 } 42 } 43 }); 44 } 45 }
测试类
1 public class RpcTest { 2 public static void main(String[] args) { 3 new Thread(new Runnable() { 4 5 @Override 6 public void run() { 7 try 8 { 9 RpcExepoter.exporter("localhost", 8080);//发布者提供ip地址和端口号 10 }catch (Exception e) { 11 e.printStackTrace(); 12 } 13 14 } 15 }).start();
//下面是本地调用 16 RpcImporter<EchoService> importer = new RpcImporter<EchoService>(); 17 EchoService echoService = importer.importer(EchoServiceImpl.class, new InetSocketAddress("localhost", 8080)); 18 System.err.println(echoService.echo("Are you ok?")); 19 } 20 }
下面是运行结果

再次说明 本文代码为原书所有 有兴趣的同学 欢迎来共同学习,共同探讨。
浙公网安备 33010602011771号