Java简单的RPC实现(一)
RPC使用java最基本的,传输层使用Socket,序列化使用Serializable,java 动态代理模式,但是未实现消息注册等相关信息
大道至简
server端
1 package com.rpc.entity; 2 3 import java.io.Serializable; 4 5 public class RpcObject implements Serializable{ 6 7 private static final long serialVersionUID = 1L; 8 private Class<?> c; 9 private String methodName; 10 private Object[] args; 11 12 public RpcObject() { 13 14 } 15 16 public RpcObject(Class<?> c, String methodName, Object[] args) { 17 this.c = c; 18 this.methodName = methodName; 19 this.args = args; 20 } 21 22 public Class<?> getC() { 23 return c; 24 } 25 26 public void setC(Class<?> c) { 27 this.c = c; 28 } 29 30 public String getMethodName() { 31 return methodName; 32 } 33 34 public void setMethodName(String methodName) { 35 this.methodName = methodName; 36 } 37 38 public Object[] getArgs() { 39 return args; 40 } 41 42 public void setArgs(Object[] args) { 43 this.args = args; 44 } 45 }
ConfMonitor
1 package com.rpc.server; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import com.rpc.service.impl.HelloImpl; 7 8 /** 9 * 模拟配置,实际的框架中大部分都是使用xml进行配置的,比如Hessian是配置在web.xml的servlet属性里的 10 * @author cdwangzijian 11 * 12 */ 13 public class ConfMonitor { 14 @SuppressWarnings("rawtypes") 15 public static Map<String, Class> conf = new HashMap<String, Class>(); 16 17 static { 18 conf.put("com.rpc.service.IHello", HelloImpl.class); 19 } 20 }
RpcThread
1 package com.rpc.server; 2 3 import java.io.IOException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 import java.lang.reflect.InvocationTargetException; 7 import java.lang.reflect.Method; 8 import java.net.Socket; 9 10 import com.rpc.entity.RpcObject; 11 12 public class RpcThread extends Thread { 13 14 private Socket s; 15 16 public RpcThread(Socket s) { 17 this.s = s; 18 } 19 20 @Override 21 public void run() { 22 23 ObjectInputStream is = null; 24 ObjectOutputStream os = null; 25 26 try { 27 28 is = new ObjectInputStream(s.getInputStream()); 29 30 // 得到远程调用参数,包含了接口名,调用方法,方法参数 31 RpcObject rpcObject = (RpcObject) is.readObject(); 32 33 System.out.println("Method:"+rpcObject.getMethodName()); 34 35 // 构建接口的实现类,然后通过反射调用方法 36 Object o = getObject(rpcObject.getC()); 37 System.out.println("class:"+rpcObject.getC()); 38 39 40 Object reO = executeMethod(o, rpcObject.getMethodName(), rpcObject.getArgs()); 41 42 // 输出返回值 43 os = new ObjectOutputStream(s.getOutputStream()); 44 os.writeObject(reO); 45 os.flush(); 46 } catch (IOException e) { 47 e.printStackTrace(); 48 } catch (ClassNotFoundException e) { 49 e.printStackTrace(); 50 } finally { 51 try { 52 if(is!=null){ 53 is.close(); 54 } 55 56 if(os!=null){ 57 os.close(); 58 } 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } 62 } 63 } 64 65 /** 66 * 通过反射技术执行方法,并返回返回值 67 * @param o 68 * @param methodName 69 * @param args 70 * @return 71 */ 72 private Object executeMethod(Object o, String methodName, Object[] args) { 73 Object objR = null; 74 Class<?>[] cs = new Class[args.length]; 75 for (int i = 0; i < args.length; i++) { 76 Object arg = args[i]; 77 cs[i] = arg.getClass(); 78 } 79 try { 80 Method m = o.getClass().getMethod(methodName, cs); 81 objR = m.invoke(o, args); 82 } catch (SecurityException e) { 83 e.printStackTrace(); 84 } catch (NoSuchMethodException e) { 85 e.printStackTrace(); 86 } catch (IllegalArgumentException e) { 87 e.printStackTrace(); 88 } catch (IllegalAccessException e) { 89 e.printStackTrace(); 90 } catch (InvocationTargetException e) { 91 e.printStackTrace(); 92 } 93 return objR; 94 } 95 96 /** 97 * 根据接口名得到实例 98 * @param c 99 * @return 100 */ 101 private Object getObject(Class<?> c) { 102 Object o = null; 103 try { 104 105 System.out.println("c.getName:"+c.getName()); 106 107 o = ConfMonitor.conf.get(c.getName()).newInstance(); 108 } catch (InstantiationException e) { 109 e.printStackTrace(); 110 } catch (IllegalAccessException e) { 111 e.printStackTrace(); 112 } 113 return o; 114 } 115 }
StartUp
1 package com.rpc.server; 2 3 import java.io.IOException; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 7 /** 8 * RPC服务器启动 9 * @author cdwangzijian 10 * 11 */ 12 public class StartUp { 13 14 public static final int port = 9001; 15 16 public static void main(String[] args) { 17 exportRpc(); 18 } 19 20 /** 21 * 导出RPC接口 22 */ 23 private static void exportRpc() { 24 try { 25 ServerSocket ss = new ServerSocket(port); 26 while(true){ 27 Socket s = ss.accept(); 28 if(s!=null){ 29 new RpcThread(s).start(); 30 } 31 } 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 } 36 }
HelloImpl
1 package com.rpc.service.impl; 2 3 import com.rpc.service.IHello; 4 5 public class HelloImpl implements IHello { 6 @Override 7 public String sayHello(String name) { 8 return "hello:" + name; 9 } 10 }
IHello
1 package com.rpc.service; 2 3 public interface IHello { 4 String sayHello(String name); 5 }
客户端实现:
ProxyFactory
1 package com.zhy.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class ProxyFactory { 7 8 @SuppressWarnings("unchecked") 9 public static <T> T create(Class<T> c, String ip, int port) { 10 11 InvocationHandler handler = new RpcProxy(ip, port, c); 12 13 return (T) Proxy.newProxyInstance(c.getClassLoader(),new Class[] {c},handler); 14 } 15 }
RpcProxy
1 package com.zhy.proxy; 2 3 import java.io.ObjectInputStream; 4 import java.io.ObjectOutputStream; 5 import java.io.Serializable; 6 import java.lang.reflect.InvocationHandler; 7 import java.lang.reflect.Method; 8 import java.net.Socket; 9 10 import com.rpc.entity.RpcObject; 11 12 /** 13 * 客户端接口代理 14 * 当客户端接口方法被调用的时候,把方法名,方法参数作为参数。 15 * 传送给远程服务执行,然后获取返回值 16 * @author cdwangzijian 17 * 18 */ 19 public class RpcProxy implements InvocationHandler, Serializable{ 20 21 private String ip; 22 private int port; 23 private Class<?> c; 24 25 private static final long serialVersionUID = 1L; 26 27 public RpcProxy(String ip, int port, Class<?> c) { 28 this.ip = ip; 29 this.port = port; 30 this.c = c; 31 } 32 33 /** 34 * 动态代理类,当调用接口方法的时候转为调用此方法 35 */ 36 @Override 37 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { 38 39 // 用作返回值 40 Object o = null; 41 // 通过socket调用远程服务 42 Socket s = new Socket(ip, port); 43 44 // 组装为一个保留了要调用的类,方法名及参数的对象,然后序列化之后传给远程 45 RpcObject rpcObject = new RpcObject(c, method.getName(), args); 46 47 ObjectOutputStream os = null; 48 ObjectInputStream is = null; 49 50 try{ 51 os = new ObjectOutputStream(s.getOutputStream()); 52 os.writeObject(rpcObject); 53 os.flush(); 54 55 // 从远程得到返回结果 56 is = new ObjectInputStream(s.getInputStream()); 57 o = is.readObject(); 58 59 } catch (Exception e) { 60 e.printStackTrace(); 61 62 } finally{ 63 64 if(os!=null){ 65 os.close(); 66 } 67 68 if(is!=null){ 69 is.close(); 70 } 71 72 } 73 74 return o; 75 } 76 77 }
RpcClient
1 package com.zhy; 2 3 import com.rpc.service.IHello; 4 import com.zhy.proxy.ProxyFactory; 5 6 public class RpcClient { 7 public static void main(String[] args) { 8 9 String ip = "localhost"; 10 int port = 9001; 11 12 IHello hello = ProxyFactory.create(IHello.class, ip, port); 13 14 System.out.println(hello.sayHello("小明")); 15 16 } 17 }
输出结果: