首先你必须了解什么是RPC, (百度知道)
RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

结构:(图片来源:cnblogs.com/shown)
rpc 原理和简单实现
  1. 1. RpcServer  
  2.    负责导出(export)远程接口  
  3. 2. RpcClient  
  4.    负责导入(import)远程接口的代理实现  
  5. 3. RpcProxy  
  6.    远程接口的代理实现  
  7. 4. RpcInvoker  
  8.    客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回  
  9.    服务方实现:负责调用服务端接口的具体实现并返回调用结果  
  10. 5. RpcProtocol  
  11.    负责协议编/解码  
  12. 6. RpcConnector  
  13.    负责维持客户方和服务方的连接通道和发送数据到服务方  
  14. 7. RpcAcceptor  
  15.    负责接收客户方请求并返回请求结果  
  16. 8. RpcProcessor  
  17.    负责在服务方控制调用过程,包括管理调用线程池、超时时间等  
  18. 9. RpcChannel  
  19.    数据传输通道  

对比本地JAVA 和 RPC代码:
1)本地模式
a)本地的接口:
package example1.day20170625;

/**
 * Created by chenfenggang on 2017/7/17.
 */
public interface Calculator {
     int sum(int a,int b);
}
b)本地的实现
package day20170625;

/**
 * Created by chenfenggang on 2017/7/17.
 */
public class MyCalculator implements  Calculator{
    public int sum(int a, int b) {
        return a+b;
    }
}
c)本地的测试
package day20170625;

/**
 * Created by chenfenggang on 2017/7/17.
 */
public class TestMyCalculator {
    public static void main(String[] args) {
        Calculator calculator = new MyCalculator();
        System.out.println(calculator.sum(1,2));
    }
}
2) 加代理。不实现方法

package day20170625;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by chenfenggang on 2017/7/17.
 */
public class MyInvocatationHandler<T> implements InvocationHandler {

    private Class target;
    MyInvocatationHandler(Class target) {
        super();
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(target);
        System.out.println(method.getName());
        System.out.println(args.length);
        for(Object object:args){
            System.out.println(object);
        }
        return 11;
    }

    public <T>T getObject(){
      return  (T)   Proxy.newProxyInstance(target.getClassLoader(),
              new Class<?>[]{target}, new MyInvocatationHandler(target)) ;
    }

    public static void main(String[] args) {
        Calculator   calculator  = (Calculator) new MyInvocatationHandler<Calculator>(Calculator.class).getObject();
        System.out.println(calculator.sum(1,2));
    }
}
这样不管调用什么都会调invoke方法。如果将这部分变成一个基于io或者nio的东西,就能读取远程的对象。

3)客户端加入Socket
package day20170625;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

/**
 * Created by chenfenggang on 2017/7/17.
 */
public class MyRpcClient<T> implements InvocationHandler {

    private Class target;
    MyRpcClient(Class target) {
        super();
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Socket socket = new Socket("localhost",8080);
        ObjectOutputStream objectOutputStream =  new ObjectOutputStream(socket.getOutputStream());
        objectOutputStream.writeObject(target.getName());
        objectOutputStream.writeObject(method.getName());
        objectOutputStream.writeObject(method.getParameterTypes());
        objectOutputStream.writeObject(args);
        return new ObjectInputStream(socket.getInputStream()).readObject();
    }

    public <T>T getObject(){
      return  (T)   Proxy.newProxyInstance(target.getClassLoader(),
              new Class<?>[]{target}, new MyRpcClient(target)) ;
    }

    public static void main(String[] args) {
        Calculator   calculator  = (Calculator) new MyRpcClient<Calculator>(Calculator.class).getObject();
        System.out.println(calculator.sum(123,10));
        System.out.println(calculator.delete(123,10));
    }
}
4)服务端读取客户端请求,反射对象
package day20170625;

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.HashMap;
import java.util.Map;

/**
 * Created by chenfenggang on 2017/7/17.
 */
public class RpcService  {
    //存储接口与实现类的关系,当然也可以通过客户端传送实现类的类名
    static Map<String ,Class>  classImpMap = new HashMap();
    public static  void put(String name,Class clazz){
        classImpMap.put(name,clazz);
    }
    public static void run() throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

        ServerSocket serverSocket = new ServerSocket(8080);

        while (true){
            Socket socket = serverSocket.accept();
            ObjectInputStream inputStream =new ObjectInputStream( socket.getInputStream());
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            String calssName = (String)inputStream.readObject();
            String methodName = (String)inputStream.readObject();
            Class<?>[] parameterTypes = (Class<?>[]) inputStream.readObject();
            Object[] arguments = (Object[]) inputStream.readObject();
            Class clazz = null;
            if(calssName!=null) {
                //需要获取接口的实现类
              clazz = classImpMap.get(calssName);
            }
            if(clazz==null){
                continue;
            }
            Method method = clazz.getMethod(methodName,parameterTypes);
            Object result = method.invoke(clazz.newInstance(), arguments);
            objectOutputStream.writeObject(result);
        }
    }

    public static void main(String[] args) {
        try {
            RpcService.put(Calculator.class.getName(),MyCalculator.class);
            RpcService.run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5)总结:
RPC优点:
1)客户端只需要接口就像,不用管复杂的实现,
2) 实现代码在服务端运行,可以充分利用服务端代码优势。

相关文章: