核心框架类

/*
* Copyright 2011 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.study.rpc.framework;
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.ServerSocket;
import java.net.Socket;
/**
* RpcFramework
*
* @author william.liangf
*/
public class RpcFramework {
   /**
    * 暴露服务
    *
    * @param service 服务实现
    * @param port 服务端口
    * @throws Exception
    */
   public static void export(final Object service, int port) throws Exception {
       if (service == null)
           throw new IllegalArgumentException("service instance == null");
       if (port <= 0 || port > 65535)
           throw new IllegalArgumentException("Invalid port " + port);
       System.out.println("Export service " + service.getClass().getName() + " on port " + port);
       ServerSocket server = new ServerSocket(port);
       for(;;) {
           try {
               final Socket socket = server.accept();
               new Thread(new Runnable() {
                   @Override
                   public void run() {
                       try {
                           try {
                               ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                               try {
                                   String methodName = input.readUTF();
                                   Class<?>[] parameterTypes = (Class<?>[])input.readObject();
                                   Object[] arguments = (Object[])input.readObject();
                                   ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                                   try {
                                       Method method = service.getClass().getMethod(methodName, parameterTypes);
                                       Object result = method.invoke(service, arguments);
                                       output.writeObject(result);
                                   } catch (Throwable t) {
                                       output.writeObject(t);
                                   } finally {
                                       output.close();
                                   }
                               } finally {
                                   input.close();
                               }
                           } finally {
                               socket.close();
                           }
                       } catch (Exception e) {
                           e.printStackTrace();
                       }
                   }
               }).start();
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
   }
   /**
    * 引用服务
    *
    * @param <T> 接口泛型
    * @param interfaceClass 接口类型
    * @param host 服务器主机名
    * @param port 服务器端口
    * @return 远程服务
    * @throws Exception
    */
   @SuppressWarnings("unchecked")
   public static <T> T refer(final Class<T> interfaceClass, final String host, final int port) throws Exception {
       if (interfaceClass == null)
           throw new IllegalArgumentException("Interface class == null");
       if (! interfaceClass.isInterface())
           throw new IllegalArgumentException("The " + interfaceClass.getName() + " must be interface class!");
       if (host == null || host.length() == 0)
           throw new IllegalArgumentException("Host == null!");
       if (port <= 0 || port > 65535)
           throw new IllegalArgumentException("Invalid port " + port);
       System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);
       return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] {interfaceClass}, new InvocationHandler() {
           public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
               Socket socket = new Socket(host, port);
               try {
                   ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                   try {
                       output.writeUTF(method.getName());
                       output.writeObject(method.getParameterTypes());
                       output.writeObject(arguments);
                       ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
                       try {
                           Object result = input.readObject();
                           if (result instanceof Throwable) {
                               throw (Throwable) result;
                           }
                           return result;
                       } finally {
                           input.close();
                       }
                   } finally {
                       output.close();
                   }
               } finally {
                   socket.close();
               }
           }
       });
   }
}

定义服务接口

/*
* Copyright 2011 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.study.rpc.test;
/**
* HelloService
*
* @author william.liangf
*/
public interface HelloService {
   String hello(String name);
}

实现服务

/*
* Copyright 2011 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.study.rpc.test;
/**
* HelloServiceImpl
*
* @author william.liangf
*/
public class HelloServiceImpl implements HelloService {
   public String hello(String name) {
       return "Hello " + name;
   }
}

暴露服务

/*
* Copyright 2011 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.study.rpc.test;
import com.alibaba.study.rpc.framework.RpcFramework;
/**
* RpcProvider
*
* @author william.liangf
*/
public class RpcProvider {
   public static void main(String[] args) throws Exception {
       HelloService service = new HelloServiceImpl();
       RpcFramework.export(service, 1234);
   }
}

引用服务

/*
* Copyright 2011 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.study.rpc.test;
import com.alibaba.study.rpc.framework.RpcFramework;
/**
* RpcConsumer
*
* @author william.liangf
*/
public class RpcConsumer {
   public static void main(String[] args) throws Exception {
       HelloService service = RpcFramework.refer(HelloService.class, "127.0.0.1", 1234);
       for (int i = 0; i < Integer.MAX_VALUE; i ++) {
           String hello = service.hello("World" + i);
           System.out.println(hello);
           Thread.sleep(1000);
       }
   }
}

总结

这个简单的例子的实现思路是使用阻塞的socket IO流来进行server和client的通信,也就是rpc应用中服务提供方和服务消费方。并且是端对端的,用端口号来直接进行通信。方法的远程调用使用的是jdk的动态代理,参数的序列化也是使用的最简单的objectStream。

真实的rpc框架会对上面的实现方式进行替换,采用更快更稳定,更高可用易扩展,更适宜分布式场景的中间件,技术来替换。例如使用netty的nio特性达到非阻塞的通信,使用zookeeper统一管理服务注册与发现,解决了端对端不灵活的劣势。代理方式有cglib字节码技术。序列化方式有hession2,fastjson等等。使用原生的jdk api就展现给各位读者一个生动形象的rpc demo,实在是强。rpc框架解决的不仅仅是技术层面的实现,还考虑到了rpc调用中的诸多问题,重试机制,超时配置…这些就需要去了解成熟的rpc框架是如果考虑这些问题的了。

推荐一个轻量级的rpc框架:motan。weibo团队在github开源的一个rpc框架,有相应的文档,用起来感觉比dubbo要轻量级,易上手。

简单了解RPC实现原理-copy的更多相关文章

  1. RPC实现原理(HSF、dubbo) 从头开始(一)

    前言 阔别了很久博客园,虽然看了以前写的很多东西感觉好幼稚,但是还是觉得应该把一些自己觉得有用的东西和大家分享.废话不多说,现在开始进入正题. 之前的六年工作经验,呆过了一些大公司,每个在大公司呆过的 ...

  2. 分布式架构的基石.简单的 RPC 框架实现(JAVA)

    前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...

  3. Java实现简单的RPC框架(美团面试)

    一.RPC简介 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用) ...

  4. 如何实现一个简单的RPC

    在如何给老婆解释什么是RPC中,我们讨论了RPC的实现思路. 那么这一次,就让我们通过代码来实现一个简单的RPC吧! RPC的实现原理 正如上一讲所说,RPC主要是为了解决的两个问题: 解决分布式系统 ...

  5. 动手实现一个简单的 rpc 框架到入门 grpc (上)

    rpc 全称 Remote Procedure Call 远程过程调用,即调用远程方法.我们调用当前进程中的方法时很简单,但是想要调用不同进程,甚至不同主机.不同语言中的方法时就需要借助 rpc 来实 ...

  6. 徒手撸一个简单的RPC框架

    来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...

  7. RPC通信原理概述

    RPC通信原理概述 1.RPC概述 1.什么是RPC RPC(Remote Procedure Call Protocol)远程过程调用协议.它是一种通过网络从远程计算机程序上请求服务,而不需要了解底 ...

  8. 聊聊RPC及其原理

    什么是RPC? RPC是Remote Procedure Call的缩写,想Client-Servier一样的远程过程调用,也就是调用远程服务就跟调用本地服务一样方便,一般用于将程序部署在不同的机器上 ...

  9. 自己用 Netty 实现一个简单的 RPC

    目录: 需求 设计 实现 创建 maven 项目,导入 Netty 4.1.16. 项目目录结构 设计接口 提供者相关实现 消费者相关实现 测试结果 总结 源码地址:github 地址 前言 众所周知 ...

  10. 最简单的RPC框架实现

    通过java原生的序列化,Socket通信,动态代理和反射机制,实现一个简单的RPC框架,由三部分组成: 1.服务提供者,运行再服务端,负责提供服务接口定义和服务实现类 2.服务发布者,运行再RPC服 ...

随机推荐

  1. Go语言创建Web服务器

    因为Go语言自带高性能服务器,且支持http.TCP/UDP,这得益于内置了net/http包,这个包提供了HTTP客户端和服务端的实现, 所以用Go语言创建Web服务器,代码很简洁. 说明: 1.导 ...

  2. k8s之容器运行时

    Kubernetes 中的容器运行时 容器运行时(Container Runtime)是 Kubernetes 最重要的组件之一,负责真正管理镜像和容器的生命周期.Kubelet 通过 Contain ...

  3. CommonsCollections6(基于ysoserial)

    环境准备 JDK1.8(8u421)我以本地的JDK8版本为准.commons-collections(3.x 4.x均可这里使用3.2版本) cc3.2: <dependency> &l ...

  4. context之WithTimeout的使用

    1. context包的WithTimeout()函数接受一个 Context 和超时时间作为参数,返回其子Context和取消函数cancel2. 新创建协程中传入子Context做参数,且需监控子 ...

  5. MySQL原理简介—9.MySQL索引原理

    大纲 1.磁盘数据页的存储结构 2.没有索引数据库如何搜索数据 3.在表中插入数据时如何进行页分裂 4.如何设计主键索引及如何根据主键索引查询 5.索引的物理存储结构 6.更新数据时自动维护的聚簇索引 ...

  6. JPEG格式研究——(4)反量化、逆ZigZag变化和IDCT变换

    反量化 反量化其实很简单,将霍夫曼解码出来的数据乘上对应的量化表就好了 通过当前色度选择出SOF中的Component,其中的Tqi指出了这一色度所需的量化表id Component的结构如下: 名称 ...

  7. 【JS篇】控制子集超过一定数量开始轮播

    [JS篇]控制子集超过一定数量开始轮播, 这个是很早的时候的一个效果了,经过代码的不断迭代升级修改,现在是最封装的一版本,通过面向对象传参数,适用于任何一个需要放置 数量达到一定条件后可执行的函数 / ...

  8. 【Android】屏幕超时休眠

    前言 屏幕超时休眠指的是在设备一段时间没有操作后,自动关闭屏幕显示以节省电量并防止误触.当屏幕进入休眠状态时,通常会关闭屏幕背光,但设备可能仍在运行后台进程. 正文 Settings应用相关 Sett ...

  9. 2024-12-18:正方形中的最多点数。用go语言,给定一个二维数组 points 和一个字符串 s,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的标签。 如果一个正

    2024-12-18:正方形中的最多点数.用go语言,给定一个二维数组 points 和一个字符串 s,其中 points[i] 表示第 i 个点的坐标,s[i] 表示第 i 个点的标签. 如果一个正 ...

  10. COS数据工作流+云函数最佳实践 - 文件哈希值计算

    01 文件哈希值是什么? 文件哈希值,即文件内容的HASH值.是通过对文件内容进行加密运算得到的一组二进制值,主要用途是用于文件校验或签名.正是因为这样的特点,它常常用来判断两个文件是否相同. COS ...