RPC: Remote Procedure Call 远程过程调用,即业务的具体实现不是在自己系统中,需要从其他系统中进行调用实现,所以在系统间进行数据交互时经常使用。

rpc的实现方式有很多,可以通过http和tcp协议进行实现

通过http协议的主要有:

  1. webService    可以参考我之前的博客  WebService 学习之路(一):了解并使用webService

webService学习之路(二):springMVC集成CXF快速发布webService

webService学习之路(三):springMVC集成CXF后调用已知的wsdl接口

  1. restful           可以参考我之前的博客  Restful 介绍及SpringMVC+restful 实例讲解

而今天要讲的是通过TCP协议实现的远程调用。

为啥已经掌握了webservice和restful等通过http协议实现rpc技术外,还要研究tcp协议实现rpc呢?

因为网络七层协议中,http位于tcp之上,而从传输上而言,越底层同等条件下传输速度更快

另外影响rpc调用的除了传输方式外,另一个就是序列化,而java的阻塞式IO往往成为瓶颈,所以这里设计到了NIO,

NIO知识点就多了,请自己搜索学习。

言归正传,今天不借助其他仁和框架,用简单的代码还原rpc的过程。

大致可以分为下面几部(先了解过程,再看代码更容易理解):

  1. 书写好服务接口和实现,就是我们项目中的业务层,看着service,service.imp就熟悉了 o(∩_∩)o
  2. 把1写好的接口暴露给其他系统,以便调用
  3. 根据暴露了接口的地址和接口信息,进行调用

是不是感觉和调用本地的service一样, 最终就是要达到的这个效果。

文采不好,就要开始贴代码了:

首先是写接口和接口的实现类,和平时看见的、写的没任何区别

接口定义

  1. package com.xiaochangwei.rpc;
  2.  
  3. public interface RpcTestService {
  4. String testRpcCall(int count);
  5. }

接口实现类

  1. package com.xiaochangwei.rpc;
  2.  
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5.  
  6. public class RpcTestServiceImpl implements RpcTestService {
  7.  
  8. public final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss");
  9.  
  10. @Override
  11. public String testRpcCall(int count) {
  12. return dateFormat.format(new Date())+" 调用rpc次数为:" + count;
  13. }
  14.  
  15. }

然后就是rpc的精髓了,怎么把服务暴露给其他系统的

其实说白了就是使用java自带的

import java.net.ServerSocket;
import java.net.Socket;

网络编程相关的东西socket和对应的IO,因为我们要向服务器发送请求,然后服务器又要返回数据给请求方,

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

同时还要用到反射,因为我们不可能每个接口实现类的暴露都去写一套方法吧,得共通化吧, 先简单理解为泛型把    代码中看见过Class T 吧 o(∩_∩)o

先简单理解为过程和socket调用过程一样吧:

  1. 根据约定的端口,服务端起一个ServerSocket,并一直监听该端口
  2. 监听到有请求时,server端通过inputStream取得请求的相关信息
  3. 根据请求信息调用相应方法处理,并返回结果

简易PRC框架

  1. package com.xiaochangwei.rpc;
  2.  
  3. import java.io.ObjectInputStream;
  4. import java.io.ObjectOutputStream;
  5. import java.lang.reflect.InvocationHandler;
  6. import java.lang.reflect.Method;
  7. import java.lang.reflect.Proxy;
  8. import java.net.ServerSocket;
  9. import java.net.Socket;
  10.  
  11. /**
  12. * rpc简易框架
  13. */
  14. public class RpcFramework {
  15.  
  16. /**
  17. * 暴露服务
  18. */
  19. @SuppressWarnings("resource")
  20. public static void export(final Object service, int port) throws Exception {
  21. if (service == null)
  22. throw new IllegalArgumentException("服务实例为空");
  23. if (port <= 0 || port > 65535)
  24. throw new IllegalArgumentException("端口号不正确");
  25. System.out.println("通过端口 [" + port +"] 暴露服务[" + service.getClass().getName() + "]" );
  26.  
  27. ServerSocket server = new ServerSocket(port);
  28. while(true){
  29. try {
  30. final Socket socket = server.accept();
  31. new Thread(new Runnable() {
  32. @Override
  33. public void run() {
  34. try {
  35. try {
  36. ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
  37. try {
  38. String methodName = inputStream.readUTF();
  39. Class<?>[] parameterTypes = (Class<?>[]) inputStream.readObject();
  40. Object[] arguments = (Object[]) inputStream.readObject();
  41. ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
  42. try {
  43. Method method = service.getClass().getMethod(methodName,parameterTypes);
  44. Object result = method.invoke(service,arguments);
  45. output.writeObject(result);
  46. } catch (Throwable t) {
  47. output.writeObject(t);
  48. } finally {
  49. output.close();
  50. }
  51. } finally {
  52. inputStream.close();
  53. }
  54. } finally {
  55. socket.close();
  56. }
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. }).start();
  62. } catch (Exception e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. }
  67.  
  68. /**
  69. * 引用服务
  70. */
  71. @SuppressWarnings("unchecked")
  72. public static <T> T refer(final Class<T> interfaceClass, final String host,
  73. final int port) throws Exception {
  74. if (interfaceClass == null)
  75. throw new IllegalArgumentException("接口为空");
  76. if (!interfaceClass.isInterface())
  77. throw new IllegalArgumentException(interfaceClass.getName() + " 不是接口");
  78. if (host == null || host.length() == 0)
  79. throw new IllegalArgumentException("主机地址为空");
  80. if (port <= 0 || port > 65535)
  81. throw new IllegalArgumentException("端口不正确" + port);
  82. System.out.println("从服务器[" + host + ":" + port + "]取得远程服务[" + interfaceClass.getName() + "]" );
  83.  
  84. return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),
  85. new Class<?>[] { interfaceClass }, new InvocationHandler() {
  86. public Object invoke(Object proxy, Method method,Object[] arguments) throws Throwable {
  87. Socket socket = new Socket(host, port);
  88. try {
  89. ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
  90. try {
  91. output.writeUTF(method.getName());
  92. output.writeObject(method.getParameterTypes());
  93. output.writeObject(arguments);
  94. ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
  95. try {
  96. Object result = input.readObject();
  97. if (result instanceof Throwable) {
  98. throw (Throwable) result;
  99. }
  100. return result;
  101. } finally {
  102. input.close();
  103. }
  104. } finally {
  105. output.close();
  106. }
  107. } finally {
  108. socket.close();
  109. }
  110. }
  111. });
  112. }
  113.  
  114. /**
  115. * 暴露RPC服务主调函数
  116. */
  117. public static void main(String[] args) throws Exception {
  118. RpcTestService rpcTestService = new RpcTestServiceImpl();
  119. RpcFramework.export(rpcTestService, 3125);
  120. }
  121. }

指定其中的main后,我们的接口就通过指定的端口暴露给其他系统了

其他系统调用也很简单

  1. package com.xiaochangwei.rpc;
  2.  
  3. public class RpcConsumer {
  4. public static void main(String[] args) throws Exception {
  5. RpcTestService rpcTestService = RpcFramework.refer(RpcTestService.class,"127.0.0.1", 3125);
  6. for (int i = 0; i < 10; i++) {
  7. String response = rpcTestService.testRpcCall(i);
  8. System.out.println(response);
  9. Thread.sleep(1000);
  10. }
  11. }
  12. }

是不是感觉和本地调用一样 o(∩_∩)o

看下效果吧,先暴露接口,再调用

执行调用

测试发现,调用是成功的 o(∩_∩)o

RPC远程过程调用学习之路(一):用最原始代码还原PRC框架的更多相关文章

  1. Vue学习之路之登录注册实例代码

    Vue学习之路之登录注册实例代码:https://www.jb51.net/article/118003.htm vue项目中路由验证和相应拦截的使用:https://blog.csdn.net/wa ...

  2. Python学习之路1☞简介及入门代码

    在学习之前,首先了解一下python的前世今生 一.python简介与发展: python 是一种面向对象的解释性计算机程序设计语言. python由荷兰人Guido van Rossum 于1989 ...

  3. 微服务框架surging学习之路——序列化 (转载https://www.cnblogs.com/alangur/p/10407727.html)

    微服务框架surging学习之路——序列化   1.对微服务的理解 之前看到在群里的朋友门都在讨论微服务,看到他们的讨论,我也有了一些自己的理解,所谓微服务就是系统里的每个服务都 可以自由组合.自由组 ...

  4. 用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中的重要应用【转】

    转自:http://blog.csdn.net/stpeace/article/details/44947925 版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则 ...

  5. jQuery学习之路(1)-选择器

    ▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...

  6. Android开发学习之路-RecyclerView滑动删除和拖动排序

    Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...

  7. webService学习之路(三):springMVC集成CXF后调用已知的wsdl接口

    webService学习之路一:讲解了通过传统方式怎么发布及调用webservice webService学习之路二:讲解了SpringMVC和CXF的集成及快速发布webservice 本篇文章将讲 ...

  8. [精品书单] C#/.NET 学习之路——从入门到放弃

    C#/.NET 学习之路--从入门到放弃 此系列只包含 C#/CLR 学习,不包含应用框架(ASP.NET , WPF , WCF 等)及架构设计学习书籍和资料. C# 入门 <C# 本质论&g ...

  9. Redis——学习之路四(初识主从配置)

    首先我们配置一台master服务器,两台slave服务器.master服务器配置就是默认配置 端口为6379,添加就一个密码CeshiPassword,然后启动master服务器. 两台slave服务 ...

随机推荐

  1. Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用(后续)

    在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]里面提到了Microsoft 身份认证,其实这也是一大块需要注意的地方,特作为后续补充这些知识点.上章是使用了Microsof ...

  2. Tesseract-OCR字符识别简介

    OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程.Tesseract:开源的OCR识别引擎,初期Tesseract引擎 ...

  3. 独立开发 一个社交 APP 的架构分享 (已实现)

    (本博客为原创:http://www.cnblogs.com/linguanh/)   My BananaCloud Android Application 前言:  这算是我的第一个 完完全全 由自 ...

  4. 小兔Java教程 - 三分钟学会Java文件上传

    今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...

  5. log4net使用手册

    1. log4net简介 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.Java平台下,它还 ...

  6. [转载]SQL Server 2008 R2安装时选择的是windows身份验证,未选择混合身份验证的解决办法

    安装过程中,SQL Server 数据库引擎设置为 Windows 身份验证模式或 SQL Server 和 Windows 身份验证模式.本文介绍如何在安装后更改安全模式. 如果在安装过程中选择&q ...

  7. NodeJs支付宝移动支付签名及验签

    非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_co ...

  8. 熊乐:H3 BPM为加速企业流程管理提供源动力

    近日,在北京·金隅喜来登酒店,H3 BPM以"让天下没有难用的流程"为主题,正式发布H3 BPM10.0版本.全新的业务流程管理系统在易用性方面大大提升,并且全面支持Java与.N ...

  9. BPM配置故事之案例7-公式计算

    行政主管发来邮件.要求物资明细表增加"单价""总价"."单价"由其审批时填写,"总价"根据"单价"与 ...

  10. 需要UWP Vendor一名

    工作地点北京,海淀,微软大厦2号楼,小冰项目组.