给我的小迷妹解释什么是RPC

   小迷妹:哥,我问你一个问题啊?

    我:啥问题啊?

   小迷妹:你最近嘴里面天天念叨的rpc 是啥啊?

   我:好,哥今天给你普及一下,什么是rpc。

   小迷妹:哇啊,哥哥你好棒啊。

   我:哈哈,还好还好,你不要这么崇拜我。

 

通俗解释RPC 是什么?

   RPC,就是Remote Procedure Call 远程过程调用 

   小迷妹:啥叫远程过程调用啊,咋搞的那么高深?

   我:我给你举个例子,就是说当你不想下楼吃饭的时候,然后拿起电话,叫了一个外卖,然后外卖小哥就把外卖送过来了,这个就是远程过程调用。

  小迷妹:哥,好像到中午了,刚好我不想下楼,那你帮我远程调用一下把。 

  我:。。。。。

 

精准解释RPC 是什么?

  现如今随着互联网的发展,更多的企业采用了分布式服务,解决了服务单点问题和服务功能一致性问题 ,以应对流量快速的增长。那么分布式服务之间 就会存在调用的问题。

举个例子

 

     

用户模块 是一个服务,交易模块 是一个服务。如果用户服务调用交易服务,因为它是分布到两个服务器上的是跨进程的,所以不能像调用本地方法那样,需要我们做一些处理,这就引入了rpc

来我们画张图

  

1.首先启动交易模块服务,会向外暴漏ip地址和port 端口号。

2.用户模块,通过动态代理,获取到接口和参数。

3.把获取到的接口和参数,以序列化的方式,调用交易模块暴漏出来的ip地址和port  底层通过网络协议,把序列化的数据,传输到交易模块。

4.交易模块,会把客户端传输过来的序列化数据,进行反序列化。

5.反序列化得到的接口和参数,在根据接口名称和参数,反射得到相应的实现类,然后调用实现类最后得到result。

6.最后把result放到数据流中,在根据刚刚建立的长连接,通过网络协议把result返回到客户端。

总结一下,rpc 主要解决以下两点:

  1. 解决分布式系统中,服务之间的调用问题。
  2. 远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。

 

手写RPC

 流程图

 

rpc-client 客户端

/**
 * Created by guyan on 2019/9/7 17:21
 */
public class RemoteInvokeHandler implements InvocationHandler {

    private String ip;

    private int port;

    public RemoteInvokeHandler(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理类");
        ReqParam param=new ReqParam();
        param.setClassName(method.getDeclaringClass().getName());
        param.setMethodName(method.getName());
        param.setParameters(args);
        System.out.println("param.toString() = " + param.toString());
        return new RpcNetSend(ip,port).send(param);
    }
}

 

/**
 * Created by guyan on 2019/9/7 17:23
 */
public class RpcNetSend {

    private String ip;

    private int port;

    public RpcNetSend(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    public Object send(ReqParam param) {
        Socket socket = null;
        ObjectOutputStream objectOutputStream = null;
        ObjectInputStream objectInputStream = null;
        Object result = null;
        try {
            socket = new Socket(ip, port);
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(param);
            objectOutputStream.flush();
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            result = objectInputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}
/**
 * Created by guyan on 2019/9/7 17:14
 */
public class RpcProxyClient {

    public <T> T clientProxy(final Class<T> interfaceClass, String ip, int port) {
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass },
                new RemoteInvokeHandler(ip, port));
    }
}
**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
        IMsgService iMsgService=new RpcProxyClient().clientProxy(IMsgService.class,"localhost",8080);
        String result = iMsgService.sayMsg("i am guyan");
        System.out.println("result = " + result);
    }
}

rpc-server 服务端:

/**
 * Created by guyan on 2019/9/7 11:15
 */
public interface IMsgService {

    String sayMsg(String msg);

    String saveUser(UserDto user);
}
/**
 * Created by guyan on 2019/9/7 12:24
 */
@RpcService(IMsgService.class)
public class IMsgServiceImpl implements IMsgService {

    @Override
    public String sayMsg(String msg) {
        System.out.println("IMsgService.sayMsg the msg is " + msg);
        return "sayMsg="+msg;
    }

    @Override
    public String saveUser(UserDto user) {
        System.out.println("IMsgService.saveUser the user is" + user);
        return "SUCCESS";
    }
}
/**
 * Created by guyan on 2019/9/8 15:33
 */
public class RpcProxyServer01 implements InitializingBean, ApplicationContextAware {

    private ExecutorService executorService = Executors.newCachedThreadPool();

    /**
     * 端口号
     */
    private int port;

    /**
     * key:serviceName value:service实例化
     */
    private ConcurrentMap<String,Object> map=new ConcurrentHashMap<>();


    public RpcProxyServer01(int port) {
        this.port = port;
    }




    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("spring bean 初始化之后");
        ServerSocket socketServer = null;
        try {
            socketServer = new ServerSocket(port);
            while (true) {
                Socket accept = socketServer.accept();
                executorService.submit(new ProcessorHandler(accept, map));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socketServer != null) {
                try {
                    socketServer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("spring 手动注入!");
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(RpcService.class);
        if (beans.isEmpty()){
            return;
        }
        for(Object bean:beans.values()){
            RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
            String serviceName = rpcService.value().getName();
            map.put(serviceName,bean);
        }
    }
}
/**
 * Created by guyan on 2019/9/7 14:03
 */
public class ProcessorHandler implements Runnable {

    private Socket socket;

    /**
     * key:serviceName value:service实例化
     */
    private ConcurrentMap<String, Object> map = new ConcurrentHashMap<>();

    public ProcessorHandler(Socket socket, ConcurrentMap<String, Object> map) {
        this.socket = socket;
        this.map = map;
    }

    @Override
    public void run() {
        System.out.println("进入处理类");
        ObjectInputStream objectInputStream = null;
        ObjectOutputStream objectOutputStream = null;
        try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            ReqParam reqParam = (ReqParam) objectInputStream.readObject();
            Object result = invoke(reqParam, map);
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(result);
            objectOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
                if (objectOutputStream != null) {
                    objectOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通过反射机制找到相应的方法
     *
     * @param param
     * @return
     */
    private Object invoke(ReqParam param, ConcurrentMap<String, Object> map) {
        System.out.println("param = " + param);
        Object service = map.get(param.getClassName());
        if (null == service) {
            throw new NullPointerException("the service is null,the service name is=[{}]" + param.getClassName());
        }
        Object[] parameters = param.getParameters(); //获取到参数
        Class<?>[] types = new Class[parameters.length]; //获取到参数类型
        for (int i = 0; i < parameters.length; i++) {
            types[i] = parameters[i].getClass(); //存到class type 数组中
        }
        Object result = null;

        try {
            Class clazz = Class.forName(param.getClassName()); //根据类名反射出class
            Method method = clazz.getMethod(param.getMethodName(), types); //class 根据方法名和参数获取相应的方法
            result = method.invoke(service, parameters); //通过传进来的实例类,和参数获取结果
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }
}
**
 * Hello world!
 */
public class App {

    public static void main(String[] args) {
        ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
        ((AnnotationConfigApplicationContext) applicationContext).start();
        System.out.println("spring 初始化成功");
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值