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 }

 

输出结果:

 

 

 

posted on 2017-09-22 16:00  csguo  阅读(4231)  评论(0编辑  收藏  举报