RPC远程过程调用学习之路(一):用最原始代码还原PRC框架
RPC: Remote Procedure Call 远程过程调用,即业务的具体实现不是在自己系统中,需要从其他系统中进行调用实现,所以在系统间进行数据交互时经常使用。
rpc的实现方式有很多,可以通过http和tcp协议进行实现
通过http协议的主要有:
- webService 可以参考我之前的博客 WebService 学习之路(一):了解并使用webService
webService学习之路(二):springMVC集成CXF快速发布webService
webService学习之路(三):springMVC集成CXF后调用已知的wsdl接口
- restful 可以参考我之前的博客 Restful 介绍及SpringMVC+restful 实例讲解
而今天要讲的是通过TCP协议实现的远程调用。
为啥已经掌握了webservice和restful等通过http协议实现rpc技术外,还要研究tcp协议实现rpc呢?
因为网络七层协议中,http位于tcp之上,而从传输上而言,越底层同等条件下传输速度更快
另外影响rpc调用的除了传输方式外,另一个就是序列化,而java的阻塞式IO往往成为瓶颈,所以这里设计到了NIO,
NIO知识点就多了,请自己搜索学习。
言归正传,今天不借助其他仁和框架,用简单的代码还原rpc的过程。
大致可以分为下面几部(先了解过程,再看代码更容易理解):
- 书写好服务接口和实现,就是我们项目中的业务层,看着service,service.imp就熟悉了 o(∩_∩)o
- 把1写好的接口暴露给其他系统,以便调用
- 根据暴露了接口的地址和接口信息,进行调用
是不是感觉和调用本地的service一样, 最终就是要达到的这个效果。
文采不好,就要开始贴代码了:
首先是写接口和接口的实现类,和平时看见的、写的没任何区别
接口定义
- package com.xiaochangwei.rpc;
- public interface RpcTestService {
- String testRpcCall(int count);
- }
接口实现类
- package com.xiaochangwei.rpc;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class RpcTestServiceImpl implements RpcTestService {
- public final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss");
- @Override
- public String testRpcCall(int count) {
- return dateFormat.format(new Date())+" 调用rpc次数为:" + count;
- }
- }
然后就是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调用过程一样吧:
- 根据约定的端口,服务端起一个ServerSocket,并一直监听该端口
- 监听到有请求时,server端通过inputStream取得请求的相关信息
- 根据请求信息调用相应方法处理,并返回结果
简易PRC框架
- package com.xiaochangwei.rpc;
- 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;
- /**
- * rpc简易框架
- */
- public class RpcFramework {
- /**
- * 暴露服务
- */
- @SuppressWarnings("resource")
- public static void export(final Object service, int port) throws Exception {
- if (service == null)
- throw new IllegalArgumentException("服务实例为空");
- if (port <= 0 || port > 65535)
- throw new IllegalArgumentException("端口号不正确");
- System.out.println("通过端口 [" + port +"] 暴露服务[" + service.getClass().getName() + "]" );
- ServerSocket server = new ServerSocket(port);
- while(true){
- try {
- final Socket socket = server.accept();
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- try {
- ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
- try {
- String methodName = inputStream.readUTF();
- Class<?>[] parameterTypes = (Class<?>[]) inputStream.readObject();
- Object[] arguments = (Object[]) inputStream.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 {
- inputStream.close();
- }
- } finally {
- socket.close();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 引用服务
- */
- @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("接口为空");
- if (!interfaceClass.isInterface())
- throw new IllegalArgumentException(interfaceClass.getName() + " 不是接口");
- if (host == null || host.length() == 0)
- throw new IllegalArgumentException("主机地址为空");
- if (port <= 0 || port > 65535)
- throw new IllegalArgumentException("端口不正确" + port);
- System.out.println("从服务器[" + host + ":" + port + "]取得远程服务[" + interfaceClass.getName() + "]" );
- 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();
- }
- }
- });
- }
- /**
- * 暴露RPC服务主调函数
- */
- public static void main(String[] args) throws Exception {
- RpcTestService rpcTestService = new RpcTestServiceImpl();
- RpcFramework.export(rpcTestService, 3125);
- }
- }
指定其中的main后,我们的接口就通过指定的端口暴露给其他系统了
其他系统调用也很简单
- package com.xiaochangwei.rpc;
- public class RpcConsumer {
- public static void main(String[] args) throws Exception {
- RpcTestService rpcTestService = RpcFramework.refer(RpcTestService.class,"127.0.0.1", 3125);
- for (int i = 0; i < 10; i++) {
- String response = rpcTestService.testRpcCall(i);
- System.out.println(response);
- Thread.sleep(1000);
- }
- }
- }
是不是感觉和本地调用一样 o(∩_∩)o
看下效果吧,先暴露接口,再调用
执行调用
测试发现,调用是成功的 o(∩_∩)o
RPC远程过程调用学习之路(一):用最原始代码还原PRC框架的更多相关文章
- Vue学习之路之登录注册实例代码
Vue学习之路之登录注册实例代码:https://www.jb51.net/article/118003.htm vue项目中路由验证和相应拦截的使用:https://blog.csdn.net/wa ...
- Python学习之路1☞简介及入门代码
在学习之前,首先了解一下python的前世今生 一.python简介与发展: python 是一种面向对象的解释性计算机程序设计语言. python由荷兰人Guido van Rossum 于1989 ...
- 微服务框架surging学习之路——序列化 (转载https://www.cnblogs.com/alangur/p/10407727.html)
微服务框架surging学习之路——序列化 1.对微服务的理解 之前看到在群里的朋友门都在讨论微服务,看到他们的讨论,我也有了一些自己的理解,所谓微服务就是系统里的每个服务都 可以自由组合.自由组 ...
- 用C代码简要模拟实现一下RPC(远程过程调用)并谈谈它在代码调测中的重要应用【转】
转自:http://blog.csdn.net/stpeace/article/details/44947925 版权声明:本文为博主原创文章,转载时请务必注明本文地址, 禁止用于任何商业用途, 否则 ...
- jQuery学习之路(1)-选择器
▓▓▓▓▓▓ 大致介绍 终于开始了我的jQuery学习之路!感觉不能再拖了,要边学习原生JavaScript边学习jQuery jQuery是什么? jQuery是一个快速.简洁的JavaScript ...
- Android开发学习之路-RecyclerView滑动删除和拖动排序
Android开发学习之路-RecyclerView使用初探 Android开发学习之路-RecyclerView的Item自定义动画及DefaultItemAnimator源码分析 Android开 ...
- webService学习之路(三):springMVC集成CXF后调用已知的wsdl接口
webService学习之路一:讲解了通过传统方式怎么发布及调用webservice webService学习之路二:讲解了SpringMVC和CXF的集成及快速发布webservice 本篇文章将讲 ...
- [精品书单] C#/.NET 学习之路——从入门到放弃
C#/.NET 学习之路--从入门到放弃 此系列只包含 C#/CLR 学习,不包含应用框架(ASP.NET , WPF , WCF 等)及架构设计学习书籍和资料. C# 入门 <C# 本质论&g ...
- Redis——学习之路四(初识主从配置)
首先我们配置一台master服务器,两台slave服务器.master服务器配置就是默认配置 端口为6379,添加就一个密码CeshiPassword,然后启动master服务器. 两台slave服务 ...
随机推荐
- Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用(后续)
在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]里面提到了Microsoft 身份认证,其实这也是一大块需要注意的地方,特作为后续补充这些知识点.上章是使用了Microsof ...
- Tesseract-OCR字符识别简介
OCR(Optical Character Recognition):光学字符识别,是指对图片文件中的文字进行分析识别,获取的过程.Tesseract:开源的OCR识别引擎,初期Tesseract引擎 ...
- 独立开发 一个社交 APP 的架构分享 (已实现)
(本博客为原创:http://www.cnblogs.com/linguanh/) My BananaCloud Android Application 前言: 这算是我的第一个 完完全全 由自 ...
- 小兔Java教程 - 三分钟学会Java文件上传
今天群里正好有人问起了Java文件上传的事情,本来这是Java里面的知识点,而我目前最主要的精力还是放在了JS的部分.不过反正也不麻烦,我就专门开一贴来聊聊Java文件上传的基本实现方法吧. 话不多说 ...
- log4net使用手册
1. log4net简介 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.Java平台下,它还 ...
- [转载]SQL Server 2008 R2安装时选择的是windows身份验证,未选择混合身份验证的解决办法
安装过程中,SQL Server 数据库引擎设置为 Windows 身份验证模式或 SQL Server 和 Windows 身份验证模式.本文介绍如何在安装后更改安全模式. 如果在安装过程中选择&q ...
- NodeJs支付宝移动支付签名及验签
非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_co ...
- 熊乐:H3 BPM为加速企业流程管理提供源动力
近日,在北京·金隅喜来登酒店,H3 BPM以"让天下没有难用的流程"为主题,正式发布H3 BPM10.0版本.全新的业务流程管理系统在易用性方面大大提升,并且全面支持Java与.N ...
- BPM配置故事之案例7-公式计算
行政主管发来邮件.要求物资明细表增加"单价""总价"."单价"由其审批时填写,"总价"根据"单价"与 ...
- 需要UWP Vendor一名
工作地点北京,海淀,微软大厦2号楼,小冰项目组.