text: (window.webpackJsonp=window.webpackJsonp||[]).push([[56],{609:function(t,s,a){"use strict";a.r(s);var e=a(23),n=Object(e.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("p",[t._v("本文阐述了自定义rpc框架需要知道理论，并探索了rpc框架需要解决的问题，并且进行了传统的RMI方式的实现。")]),t._v(" "),a("h1",{attrs:{id:"自定义rpc框架之分布式架构网络通信理论"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#自定义rpc框架之分布式架构网络通信理论"}},[t._v("#")]),t._v(" 自定义RPC框架之分布式架构网络通信理论")]),t._v(" "),a("blockquote",[a("p",[t._v("2022/03/14 校对完成")]),t._v(" "),a("p",[t._v("文章更新历史")]),t._v(" "),a("p",[t._v("2022/03/14 初稿。")]),t._v(" "),a("p",[t._v("2022/03/25 修复图片问题。")])]),t._v(" "),a("h2",{attrs:{id:"分布式架构网络通信"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#分布式架构网络通信"}},[t._v("#")]),t._v(" 分布式架构网络通信")]),t._v(" "),a("p",[t._v("分布式的基础问题是远程服务是怎么通讯的。")]),t._v(" "),a("p",[a("code",[t._v("java")]),t._v(" 领域有很多可实现远程通讯的技术，例如："),a("code",[t._v("RMI")]),t._v(" 、"),a("code",[t._v("Hessian")]),t._v(" 、"),a("code",[t._v("SOAP")]),t._v(" 、"),a("code",[t._v("ESB")]),t._v(" 和 "),a("code",[t._v("JMS")]),t._v(" 等。")]),t._v(" "),a("h3",{attrs:{id:"远程通讯技术"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#远程通讯技术"}},[t._v("#")]),t._v(" 远程通讯技术")]),t._v(" "),a("h4",{attrs:{id:"rmi"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rmi"}},[t._v("#")]),t._v(" RMI")]),t._v(" "),a("p",[t._v("JDK的RMI文档："),a("a",{attrs:{href:"https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/"),a("OutboundLink")],1)]),t._v(" "),a("h4",{attrs:{id:"hessian"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#hessian"}},[t._v("#")]),t._v(" Hessian")]),t._v(" "),a("p",[t._v("Hessian官网："),a("a",{attrs:{href:"http://hessian.caucho.com/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://hessian.caucho.com/"),a("OutboundLink")],1)]),t._v(" "),a("h4",{attrs:{id:"soap"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#soap"}},[t._v("#")]),t._v(" SOAP")]),t._v(" "),a("p",[t._v("SOAP："),a("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E7%AE%80%E5%8D%95%E5%AF%B9%E8%B1%A1%E8%AE%BF%E9%97%AE%E5%8D%8F%E8%AE%AE",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://zh.wikipedia.org/wiki/%E7%AE%80%E5%8D%95%E5%AF%B9%E8%B1%A1%E8%AE%BF%E9%97%AE%E5%8D%8F%E8%AE%AE"),a("OutboundLink")],1)]),t._v(" "),a("ul",[a("li",[a("p",[t._v("WSDL WS-* are language-agnostic.")])]),t._v(" "),a("li",[a("p",[t._v("JAX-WS are Java standard to build web service.")])]),t._v(" "),a("li",[a("p",[a("a",{attrs:{href:"http://cxf.apache.org/docs/why-cxf.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apache CXF"),a("OutboundLink")],1),t._v(" and "),a("a",{attrs:{href:"http://axis.apache.org/axis2/java/core/",target:"_blank",rel:"noopener noreferrer"}},[t._v("Apache Axis 2"),a("OutboundLink")],1),t._v(" are two implementations of JAX-WS. They also offer JAX-RS implementations so that you can build Restful services.")])]),t._v(" "),a("li",[a("p",[t._v("CXF has better integration with Spring, and Camel("),a("a",{attrs:{href:"http://camel.apache.org/components.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("camel-cxf"),a("OutboundLink")],1),t._v("). And Axis 2 seems not have a active release.")])]),t._v(" "),a("li",[a("p",[a("a",{attrs:{href:"https://github.com/eclipse-ee4j/jersey",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/eclipse-ee4j/jersey"),a("OutboundLink")],1)])]),t._v(" "),a("li",[a("p",[a("a",{attrs:{href:"https://cxf.apache.org/index.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://cxf.apache.org/index.html"),a("OutboundLink")],1)])]),t._v(" "),a("li",[a("p",[a("a",{attrs:{href:"https://github.com/apache/axis-axis2-java-core",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/apache/axis-axis2-java-core"),a("OutboundLink")],1)])])]),t._v(" "),a("h4",{attrs:{id:"esb"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#esb"}},[t._v("#")]),t._v(" ESB")]),t._v(" "),a("p",[t._v("ESB："),a("a",{attrs:{href:"https://zh.wikipedia.org/wiki/%E4%BC%81%E4%B8%9A%E6%9C%8D%E5%8A%A1%E6%80%BB%E7%BA%BF",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://zh.wikipedia.org/wiki/%E4%BC%81%E4%B8%9A%E6%9C%8D%E5%8A%A1%E6%80%BB%E7%BA%BF"),a("OutboundLink")],1)]),t._v(" "),a("ul",[a("li",[a("p",[t._v("Spring Integration："),a("a",{attrs:{href:"https://spring.io/projects/spring-integration",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://spring.io/projects/spring-integration"),a("OutboundLink")],1)])]),t._v(" "),a("li",[a("p",[t._v("Mule ESB："),a("a",{attrs:{href:"https://www.mulesoft.com/resources/esb/what-mule-esb",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://www.mulesoft.com/resources/esb/what-mule-esb"),a("OutboundLink")],1)])]),t._v(" "),a("li",[a("p",[t._v("Apache Camel："),a("a",{attrs:{href:"https://camel.apache.org/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://camel.apache.org/"),a("OutboundLink")],1)])])]),t._v(" "),a("h4",{attrs:{id:"jms"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#jms"}},[t._v("#")]),t._v(" JMS")]),t._v(" "),a("p",[t._v("JMS："),a("a",{attrs:{href:"https://www.oracle.com/java/technologies/java-message-service.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://www.oracle.com/java/technologies/java-message-service.html"),a("OutboundLink")],1)]),t._v(" "),a("p",[a("a",{attrs:{href:"https://spring.io/guides/gs/messaging-jms/",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://spring.io/guides/gs/messaging-jms/"),a("OutboundLink")],1)]),t._v(" "),a("ul",[a("li",[t._v("Spring JMS is the Spring abstraction over the JMS API.")]),t._v(" "),a("li",[t._v("JMS is just an API; you need a physical broker to actually do messaging.")]),t._v(" "),a("li",[t._v("ActiveMQ is not a framework, it is an open-source JMS broker that supports the actual persistence and delivery of messages.")]),t._v(" "),a("li",[t._v("Spring JMS can be used with any JMS broker, including ActiveMQ. Each broker provides its own JMS API client jar.")]),t._v(" "),a("li",[t._v("RabbitMQ is not a native JMS broker; its native protocol is AMQP 0.9.1; it does, however, provide a JMS API client that can be used with Spring JMS, but Spring AMQP is the preferred library for talking to RabbitMQ because it provides much more functionality than is available over JMS.")]),t._v(" "),a("li",[t._v("There are lots of examples for using Spring JMS on the internet.")]),t._v(" "),a("li",[t._v("The simplest way to get started is with Spring Boot and "),a("code",[t._v("@JmsListener")]),t._v(".")])]),t._v(" "),a("h3",{attrs:{id:"基本原理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#基本原理"}},[t._v("#")]),t._v(" 基本原理")]),t._v(" "),a("p",[t._v("从网络通信的底层去看，通信要做的事情就是把流从一台计算机传输到另外一台计算机。使用传输协议和网络IO实现，传输协议比较知名的如 "),a("code",[t._v("TCP")]),t._v(" 、"),a("code",[t._v("UDP")]),t._v(" 等。")]),t._v(" "),a("p",[a("code",[t._v("TCP")]),t._v(" 和 "),a("code",[t._v("UDP")]),t._v(" 都是在基于 "),a("code",[t._v("socket")]),t._v(" 的概念上为某类应用场景扩展出来的传输层协议。")]),t._v(" "),a("p",[t._v("网络 "),a("code",[t._v("IO")]),t._v(" 主要由 "),a("code",[t._v("bio")]),t._v(" 、"),a("code",[t._v("nio")]),t._v("、"),a("code",[t._v("aio")]),t._v("，所有的分布式都是基于这个原理实现的。")]),t._v(" "),a("h3",{attrs:{id:"什么是rpc"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#什么是rpc"}},[t._v("#")]),t._v(" 什么是RPC")]),t._v(" "),a("p",[t._v("rpc全称是 "),a("code",[t._v("remote procedure call")]),t._v(" ，既远程过程调用。借助 "),a("code",[t._v("RPC")]),t._v(" 可以做到像本地调用一样调用远程服务，是一种进程间的通信方式。")]),t._v(" "),a("p",[a("code",[t._v("RPC")]),t._v(" 不是一个具体的技术，而是指整个网络调用的过程。")]),t._v(" "),a("p",[t._v("下面展示的是本地调用和远程调用的示例：")]),t._v(" "),a("p",[t._v("例如有A服务器部署了一个应用，B服务器也部署了一个应用，现在A服务器上的应用想要调用B服务器上的应用的方法，由于，两个应用不在同一个服务器，因此不在同一个内存空间，无法实现直接调用，需要通过网络来表达调用的语义和传达调用的数据。")]),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463113.jpg"}}),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463123.jpg"}}),t._v(" "),a("h3",{attrs:{id:"rpc架构"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rpc架构"}},[t._v("#")]),t._v(" RPC架构")]),t._v(" "),a("p",[t._v("一个完整的RPC架构包含四个完整的组件，分表是Client，Client Stub，Server和Server Stub。Stub可以理解为存根。")]),t._v(" "),a("ul",[a("li",[t._v("客户端（Client），服务的调用方。")]),t._v(" "),a("li",[t._v("客户端存根（Client Stub），存放服务端的地址消息，将客户端的请求打包成网络消息，通过网络远程发送给服务方。")]),t._v(" "),a("li",[t._v("服务端（Server），真正的服务端提供者。")]),t._v(" "),a("li",[t._v("服务端存根（Sever Stub），接收客户端发送过来的消息，将消息解包，并调用本地方法。")])]),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463136.png"}}),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463152.png"}}),t._v(" "),a("p",[t._v("1、客户端以本地方式调用服务")]),t._v(" "),a("p",[t._v("2、客户端存根接收到调用之后，将方法参数组装成能进行网络传输的消息体，消息体序列化为二进制")]),t._v(" "),a("p",[t._v("3、客户端通过"),a("code",[t._v("socket")]),t._v("将消息发送到服务端")]),t._v(" "),a("p",[t._v("4、服务端存根接收到消息之后进行解码，将消息对象反序列化")]),t._v(" "),a("p",[t._v("5、服务端存根根据解码结果调用本地服务")]),t._v(" "),a("p",[t._v("6、服务处理")]),t._v(" "),a("p",[t._v("7、本地服务执行并将结果返回给服务端存根")]),t._v(" "),a("p",[t._v("8、服务端存根将返回结果打包成消息，将结果消息对象序列化")]),t._v(" "),a("p",[t._v("9、服务端通过socket将消息发送到客户端")]),t._v(" "),a("p",[t._v("10、客户端存根接收到消息并进行解码，将消息对象反序列化")]),t._v(" "),a("p",[t._v("11、客户端得到最终结果")]),t._v(" "),a("p",[t._v("RPC的目标是只保留1、6、11，将其他的细节全部封装起来。")]),t._v(" "),a("p",[t._v("注意：不管是什么类型的数据，在输出过程中都要转换成二进制流，而接收方需要将二进制流恢复为对象。")]),t._v(" "),a("p",[t._v("Java中常见的RPC框架有Hessian、gRPC、Dubbo等，核心模块都是通讯和序列化")]),t._v(" "),a("p",[a("a",{attrs:{href:"https://github.com/grpc/grpc-java",target:"_blank",rel:"noopener noreferrer"}},[t._v("https://github.com/grpc/grpc-java"),a("OutboundLink")],1)]),t._v(" "),a("h3",{attrs:{id:"rmi-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rmi-2"}},[t._v("#")]),t._v(" RMI")]),t._v(" "),a("p",[t._v("Java的RMI指的是 "),a("code",[t._v("Remote Method Invocation")]),t._v("，一种实现远程过程调用（RPC）的API，能直接传输序列化后的Java对象。它的实现依赖于JVM，因此它能支撑一个JVM到另外一个JVM的调用。")]),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463168.jpg"}}),t._v(" "),a("p",[t._v("1、客户端从远程服务器的注册表中查询并获取远程对象的引用。")]),t._v(" "),a("p",[t._v("2、桩对象与远程对象有相同的接口和方法列表，当客户端调用远程对象时候，实际上是由桩对象代理完成。")]),t._v(" "),a("p",[t._v("3、远程引用层将桩的本地引用转换为服务器上对象的远程引用，再将调用层传递给传输层，由传输层通过TCP协议发起调用。")]),t._v(" "),a("p",[t._v("4、在服务端，传输层监听入站链接，收到客户端的远程调用之后，将引用转发到上层的远程引用层；")]),t._v(" "),a("p",[t._v("服务端的远程引用层将客户端发送的远程引用转换为本地虚拟机的引用，再将请求传递给骨架；")]),t._v(" "),a("p",[t._v("骨架读取参数，将请求传递给服务器，由服务器进行实际的方法调用。")]),t._v(" "),a("p",[t._v('5、如果远程方法调用之后有返回值，服务器将结果沿着 "骨架->远程引用层->传输层" 向下传递。')]),t._v(" "),a("p",[t._v('6、客户端的传输层接收到返回值之后，又沿着 "传输层->远程引用层->桩" 向上传递，并最终将结果传递给客户端程序。')]),t._v(" "),a("h3",{attrs:{id:"rmi实例需求分析"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#rmi实例需求分析"}},[t._v("#")]),t._v(" RMI实例需求分析")]),t._v(" "),a("p",[t._v("1、服务端提供根据ID查询用户的方法")]),t._v(" "),a("p",[t._v("2、客户端调用服务端方法，并返回用户对象")]),t._v(" "),a("p",[t._v("3、要求使用RMI进行远程通讯")]),t._v(" "),a("h4",{attrs:{id:"服务端实现"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#服务端实现"}},[t._v("#")]),t._v(" 服务端实现")]),t._v(" "),a("div",{staticClass:"language-java line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * RMI服务端\n *\n * @name: RMIServer\n * @author: terwer\n * @date: 2022-03-06 02:01\n **/")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RMIServer")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" args"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("try")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n            "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 1.注册Registry实例，绑定端口")]),t._v("\n            "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Registry")]),t._v(" registry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LocateRegistry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("createRegistry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9998")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n            "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 2.创建远程对象")]),t._v("\n            "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IUserService")]),t._v(" userService "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("new")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("UserServiceImpl")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n            "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 3.将远程对象注册到RMI服务器（既服务端注册表）")]),t._v("\n            registry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("rebind")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"userService"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" userService"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n            "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"RMI服务端启动成功"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("catch")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RemoteException")]),t._v(" e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n            e"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("printStackTrace")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br"),a("span",{staticClass:"line-number"},[t._v("11")]),a("br"),a("span",{staticClass:"line-number"},[t._v("12")]),a("br"),a("span",{staticClass:"line-number"},[t._v("13")]),a("br"),a("span",{staticClass:"line-number"},[t._v("14")]),a("br"),a("span",{staticClass:"line-number"},[t._v("15")]),a("br"),a("span",{staticClass:"line-number"},[t._v("16")]),a("br"),a("span",{staticClass:"line-number"},[t._v("17")]),a("br"),a("span",{staticClass:"line-number"},[t._v("18")]),a("br"),a("span",{staticClass:"line-number"},[t._v("19")]),a("br"),a("span",{staticClass:"line-number"},[t._v("20")]),a("br"),a("span",{staticClass:"line-number"},[t._v("21")]),a("br"),a("span",{staticClass:"line-number"},[t._v("22")]),a("br"),a("span",{staticClass:"line-number"},[t._v("23")]),a("br")])]),a("h4",{attrs:{id:"客户端实现"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#客户端实现"}},[t._v("#")]),t._v(" 客户端实现")]),t._v(" "),a("div",{staticClass:"language-java line-numbers-mode"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * RMI客户端\n *\n * @name: RMIClient\n * @author: terwer\n * @date: 2022-03-06 19:25\n **/")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RMIClient")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("void")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("main")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" args"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("throws")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("RemoteException")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("NotBoundException")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 1、获取Registry实例")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Registry")]),t._v(" registry "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LocateRegistry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRegistry")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"127.0.0.1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("9998")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 2、通过Registry查找远程对象")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IUserService")]),t._v(" userService "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("IUserService")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" registry"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("lookup")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"userService"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("User")]),t._v(" user "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" userService"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getUserById")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n        "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("System")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("out"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("println")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"userName = "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" user"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n    "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n")])]),t._v(" "),a("div",{staticClass:"line-numbers-wrapper"},[a("span",{staticClass:"line-number"},[t._v("1")]),a("br"),a("span",{staticClass:"line-number"},[t._v("2")]),a("br"),a("span",{staticClass:"line-number"},[t._v("3")]),a("br"),a("span",{staticClass:"line-number"},[t._v("4")]),a("br"),a("span",{staticClass:"line-number"},[t._v("5")]),a("br"),a("span",{staticClass:"line-number"},[t._v("6")]),a("br"),a("span",{staticClass:"line-number"},[t._v("7")]),a("br"),a("span",{staticClass:"line-number"},[t._v("8")]),a("br"),a("span",{staticClass:"line-number"},[t._v("9")]),a("br"),a("span",{staticClass:"line-number"},[t._v("10")]),a("br"),a("span",{staticClass:"line-number"},[t._v("11")]),a("br"),a("span",{staticClass:"line-number"},[t._v("12")]),a("br"),a("span",{staticClass:"line-number"},[t._v("13")]),a("br"),a("span",{staticClass:"line-number"},[t._v("14")]),a("br"),a("span",{staticClass:"line-number"},[t._v("15")]),a("br"),a("span",{staticClass:"line-number"},[t._v("16")]),a("br"),a("span",{staticClass:"line-number"},[t._v("17")]),a("br")])]),a("h4",{attrs:{id:"效果预览"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#效果预览"}},[t._v("#")]),t._v(" 效果预览")]),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463195.png",alt:"image-20220306193226744"}}),t._v(" "),a("img",{staticStyle:{zoom:"50%"},attrs:{src:"https://cdn.jsdelivr.net/gh/terwer/upload/img/16467573463236.png",alt:"image-20220306193244530"}})])}),[],!1,null,null,null);s.default=n.exports}}]);