RPC远程过程调用底层原理分析

服务器通过socket获取到请求url(socket包含ip、端口号)。通过反射机制获取类中的方法及参数类型,然后使用url实例化一个类的对象,用该对象执行对应的方法。

客户端,首先获取服务器的ip地址及端口号。然后给服务器传送一个url,要调用的方法名及要传的参数。再通过同一端口获取执行结果。下面是源码:

服务端:

StartUp:

public class StartUp {
    
    
    
    public static final int port = 9001;
    
    public static void main(String[] args) {
    
    
            exportRpc();
    }
 
    private static void exportRpc() {
    
    
        try {
    
    
            ServerSocket ss = new ServerSocket(port);
            System.out.println("server is running....");
            while(true){
    
    
                Socket s = ss.accept() ; //采用TcP协议
                if(s!=null){
    
    
                    new RpcThread(s).start();
                }
            }
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

RpcThread:

public class RpcThread extends Thread {
    
    
    
    private Socket socket;
    
    public RpcThread(Socket socket) {
    
    
        this.socket = socket;
    }
    
    @Override
    public void run() {
    
    
        
        ObjectInputStream is = null;
        ObjectOutputStream os = null;
        
        try {
    
    
            
            //从TcP报文获取数据
            is = new ObjectInputStream(socket.getInputStream());
            
            // 得到远程调用参数,包含了接口名,调用方法,方法参数
            RpcObject rpcObject = (RpcObject) is.readObject();
            
            System.out.println("Method:"+rpcObject.getMethodName());
            
            // 构建接口的实现类,然后通过反射调用方法
            Object o = getObject(rpcObject.getUrl());
            System.out.println("class:"+rpcObject.getUrl());
            
            
            Object reO = executeMethod(o, rpcObject.getMethodName(), rpcObject.getArgs());
            
            // 输出返回值
            os = new ObjectOutputStream(socket.getOutputStream());
            os.writeObject(reO);
            os.flush();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                if(is!=null){
    
    
                    is.close();
                }
                
                if(os!=null){
    
    
                    os.close();
                }                
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 通过反射技术执行方法,并返回返回值
     */
    private Object executeMethod(Object o, String methodName, Object[] args) {
    
    
       
        Object objR = null;
      
        Class<?>[] cs = new Class[args.length];
       
        for (int i = 0; i < args.length; i++) {
    
    
            Object arg = args[i];
            cs[i] = arg.getClass();
        }
        try {
    
    
            //获取类的方法;
            Method m = o.getClass().getMethod(methodName, cs);
             //动态调用该方法
            objR = m.invoke(o, args);
        } catch (SecurityException e) {
    
    
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
    
    
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
    
    
            e.printStackTrace();
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        }
        return objR;
    }
    
    /*
     * 根据url得到实例
     */
    private Object getObject(String url) {
    
    
        Object object = null;
        try {
    
    
            Class clz=Class.forName(url);
                     
            object = clz.newInstance();
        } catch (InstantiationException e) {
    
    
            e.printStackTrace();
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        }catch(Exception e)
        {
    
    
            e.printStackTrace();
        }
        return object ;
    }
}

客户端:

RpcProxy:

public class RpcProxy implements InvocationHandler,
   Serializable{
    
    
    
    private String ip;
    private int port;
    private String url;
    
    private static final long serialVersionUID = 1L;

    public RpcProxy(String ip, int port, String url) {
    
    
        this.ip = ip;
        this.port = port;
        this.url = url;
    }
    
    /**
     * 动态代理类,当调用接口方法的时候转为调用此方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args
            )throws Throwable {
    
    
        
        // 用作返回值
        Object o = null;        
        // 通过socket调用远程服务
        Socket s = new Socket(ip, port);
        
        // 组装为一个保留了要调用的类,方法名及参数的对象,然后序列化之后传给远程
        RpcObject rpcObject = new RpcObject(url, method.getName(), args);
        
        ObjectOutputStream os = null;
        ObjectInputStream is = null;
        
        try{
    
    
            //在socket输入流建立对象流
            os = new ObjectOutputStream(s.getOutputStream());
            os.writeObject(rpcObject);// 把对象序列化,发送到服务端;
            os.flush();// 马上发送
            
            // 从远程得到返回结果
          //在socket输入流建立对象流
            is = new ObjectInputStream(s.getInputStream());
            o = is.readObject(); // 反序列化,获取结果
            
        } catch (Exception e) {
    
    
            e.printStackTrace();
            
        } finally{
    
           
            if(os!=null){
    
    
                os.close();
            }        
            if(is!=null){
    
    
                is.close();
            }
        }    
        return o;
    }
}


entities类:

RpcObject:

public class RpcObject implements Serializable{
    
    
    
    private static final long serialVersionUID = 1L;

    private String url;
    private String methodName;
    private Object[] args;
    
    public RpcObject() {
    
    
        
    }
    
    public RpcObject(String c, String methodName, Object[] args) {
    
    
        this.url = c;
        this.methodName = methodName;
        this.args = args;
    }
    
 
    public String getUrl() {
    
    
        return url;
    }

    public void setClass4Name(String url) {
    
    
        this.url = url;
    }

    public String getMethodName() {
    
    
        return methodName;
    }
    
    public void setMethodName(String methodName) {
    
    
        this.methodName = methodName;
    }
    
    public Object[] getArgs() {
    
    
        return args;
    }
    
    public void setArgs(Object[] args) {
    
    
        this.args = args;
    }
}


被远程调用的方法:

public class Hello {
    
    
    public String sayHello(String name) {
    
    
        return "hello->>>>>>:" + name;
    }
}

Main方法:

public class App2 {
    
    

    public static Object test(String ip,int port,String msg)
    {
    
    
        
        String url="com.gbs.util.Hello";
        String methodName="sayHello";
        Object args[]={
    
    msg};
        // 用作返回值
        Object o = null;        
        // 通过socket调用远程服务
        try{
    
    
        Socket s = new Socket(ip, port);
        
        // 组装为一个保留了要调用的类,方法名及参数的对象,然后序列化之后传给远程
        RpcObject rpcObject = new RpcObject(url, methodName, args);
        
        ObjectOutputStream os = null;
        ObjectInputStream is = null;
        
        try{
    
    
            os = new ObjectOutputStream(s.getOutputStream());
            os.writeObject(rpcObject);
            os.flush();
            
            // 从远程得到返回结果
            is = new ObjectInputStream(s.getInputStream());
            o = is.readObject();
            
        } catch (Exception e) {
    
    
            e.printStackTrace();
            
        }
        }
        catch(Exception e)
        {
    
    
            e.printStackTrace();
        }
        return o;
    }
    
    public static void main(String[] args) {
    
    
          System.out.println(test("localhost",9001,"helloworld").toString());
    }

}

猜你喜欢

转载自blog.csdn.net/GBS20200720/article/details/121174492
今日推荐