简单RPC之Socket实现

来源:互联网 发布:centos rpm snmp 编辑:程序博客网 时间:2024/05/19 19:57

最近看到Dubbo大神写得使用Socket实现的简单的RPC调用,对RPC的理解更简单了,然后根据大神的代码自己也重构了一下。

RPC Server端代码,主要是使用ServerSocket获得rpc调用客户端发送过来的类信息,方法信息及方法参数信息,通过反射在RPCServer端进行代码执行,最后将执行结果发送给Socket,第一步需要首先执行RPCServer。

import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.ConcurrentHashMap;/** * 服务端 * @author tianjunwei */public class RPCServer {public static ConcurrentHashMap<String, Object> classMap = new ConcurrentHashMap<String,Object>();public static void main(String [] args) throws Exception{System.err.println("server start");RPCServer.invoker(8080);}public static void invoker(int port) throws Exception{ServerSocket server = new ServerSocket(port);for(;;){try{final Socket socket = server.accept();new Thread(new Runnable() {ObjectOutputStream output =  null;@Overridepublic void run() {try{try {output = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream input = new ObjectInputStream(socket.getInputStream());String className = input.readUTF();String methodName = input.readUTF();Class<?>[] parameterTypes = (Class<?>[])input.readObject();                          Object[] arguments = (Object[])input.readObject();  Object claszz = null;if(!classMap.containsKey(className)){try {claszz = Class.forName(className).newInstance();classMap.put(className, claszz);} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {e.printStackTrace();}}else {claszz = classMap.get(className);}Method method = claszz.getClass().getMethod(methodName, parameterTypes);                          Object result = method.invoke(claszz, arguments);                          output.writeObject(result);  } catch (IOException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {output.writeObject(e);}finally {output.close();}}catch(Exception e){e.printStackTrace();}finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}).start();}catch (Exception e) {e.printStackTrace();}}}}

RPC 客户端代码,这里利用了代理机制的特性,在执行具体的方法时执行远程调用,执行方法时会调用invoke方法,这样就可以通过Socket向RPCServer发送需要执行的方法的信息,并且获取执行后的结果并返回。

public class RPCProxy { @SuppressWarnings("unchecked")public static <T> T create(Object target){  return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler(){@SuppressWarnings("resource")@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable { Socket socket = new Socket("localhost", 8080); ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());                   try {                   output.writeUTF(target.getClass().getName());                     output.writeUTF(method.getName());                       output.writeObject(method.getParameterTypes());                       output.writeObject(args);                       ObjectInputStream input = new ObjectInputStream(socket.getInputStream());                       try {                           Object result = input.readObject();                           if (result instanceof Throwable) {                               throw (Throwable) result;                           }                           return result;                       } finally {                           input.close();                       }                   } finally {                       output.close();                       socket.close();                 }  }  }); }}

HelloRpc接口:

public interface HelloRpc {String hello(String name);}
HelloRpcImpl实现类:

public class HelloRpcImpl implements HelloRpc {@Overridepublic String hello(String name) {return "hello "+name;}}

Main函数操作:

public class Main {public static void main(String [] args){HelloRpc helloRpc = new HelloRpcImpl();helloRpc = RPCProxy.create(helloRpc);System.err.println(helloRpc.hello("rpc"));}}


执行结果:

hello rpc

通过以上这个示例我们可能会对一些RPC框架的实现原理有一定的了解,比如和我之前发表的Hessian源码分析有一些相似的地方。示例源码地址github,当然这个实现只是作为一些简单的原理说明,还有很多不足的地方。







1 0
原创粉丝点击