RPC远程调用

简介

PRC是一种调用方式而不是一种协议
在这里插入图片描述
在本地调用方式时由于方法在同一个内存空间,所以程序中可以直接调用该方法,但是浏览器端和服务端程序是不在一个内存空间的,需要使用网络来访问,就需要使用TCP或者UDP协议,由于TPC协议是面向连接,基于字节流的,使用起来不太方便,于是在此基础上衍生了http,gprc等协议。

RPC协议底层可以使用http协议或者TCP协议。

为什么需要rpc协议:
在这里插入图片描述
在这里插入图片描述

RPC协议是主机之间的调用协议,HTTP是浏览器和主机之间的调用协议。

不同主机之间服务远程调用时由于需要通过网络,所以需要定义很多规则,RPC远程调用方式就是希望远程调用方法时像本地调用方法一样省去过多的细节。基于远程调用方式也衍生一些协议如,gPRC,thrift。

在这里插入图片描述

HtppClient

在这里插入图片描述
HttpClinet就是在服务器端通过Java代码模拟一个小型浏览器,获取获取数据后进行序列化与反序列化操作。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

注意是Apache的HttpClinet

在这里插入图片描述

  • 控制器服务
@RestController
@RequestMapping("/test")
public class TestControoler {
    @GetMapping("/hello")
    String Hello(){
        return "Hello";
    }
}
  • HttpClient远程代用服务
@RestController
@RequestMapping("/http")
public class HttpCilentController {
    
    @GetMapping("/getHello")
    String gethello(){
        //声明响应类
        HttpResponse execute = null;
        //创建http服务端实例
        HttpClient client = HttpClients.createDefault();
        //发送请求
        HttpGet get = new HttpGet("http://localhost:8080/test/hello");
        try {
             execute = client.execute(get);
        }catch (IOException e){ e.printStackTrace();}
        //获取响应体
        HttpEntity entity = execute.getEntity();
        //工具了解析
        String str = null;
        try {
            str = EntityUtils.toString(entity, "utf-8");
        }catch (IOException e){e.printStackTrace();}
        //这里的String就是一个json字符串,如果该字符串是一个类免责需要再次使用工具如jackson,fastjson将josn字符串转为类。

        return str;
    }
    
}

在这里插入图片描述
在这里插入图片描述

在B远程调用的A过程中,实际上是在B的服务内部实现了一个浏览器服务请求服务器返回JSON字符。

RestTemplate

RestTemplate是基于spring封装的HttpClient。在任何Java项目导入httpclient依赖后就可以使用。RestTemplate只能在spring项目中使用,并且spring本身封装了HttpClient,使用起来也更方便。

HttpClient是一种用于发送HTTP请求的原生Java库,Apache Commons HttpClient是建立在HttpClient基础上的第三方工具类库,RestTemplate是Spring框架中封装的HTTP请求操作类,Feign是一种声明式的Web服务客户端,Forest是一个为微服务开发而编写的客户端应用程序框架,他们的实现都是基于HttpClient的。

在后续的学习中还会接触到spring cloud的Feign。另外还有其他框架对HttpClient封装是其操作更加方便。如Forest,okhttp等。除了OkHttp只支持HTTP请求外,其他工具都支持Http和https协议。不同的是,HttpClient和Forest是对同一个底层框架的封装,在性能上比Okhttp要好很多;RestTemplate和Feign都是基于Spring框架的封装,支持并发,实现起来更易于维护。

@RestController
@RequestMapping("/template")
public class TemplateControoler {
    RestTemplate restTemplate = new RestTemplate();
    @GetMapping("/getHello")
    String getStr(){
        String str = restTemplate.getForObject("http://localhost:8080/test/hello",String.class);
        return str;
    }
}

在spring中只需要少量的代码就可以完成功能,更加方便简洁。

在这里插入图片描述

RMI

RMI: 远程方法调用(Remote Method Invocation),它支持存储于不同地址空间的程序级对象之间彼此进行通信,实现远程对象之间的无缝远程调用。

在这里插入图片描述

前两种实现RPC的方式是基于HTTP协议的,那么就需要在服务端模拟浏览器请求。RMI是直接基于TCP协议的。

在这里插入图片描述
Java RMI: 用于不同虚拟机之间的通信,这些虚拟机可以在不同的主机上、也可以在同一个主机上;一个虚拟机中的对象调用另一个虚拟上中的对象的方法,只不过是允许被远程调用的对象要通过一些标志加以标识,底层是通过Socket通信来进行实现的。

在这里插入图片描述

  • 返回类
class Person{
    private String name;
    private int age;
    private String address;


    Person(String name,int age,String address){
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
  • 控制器
@RestController
@RequestMapping("/rmi")
public class RmiControoler {
    @GetMapping("/hello")
    String Hello(){
        return "Hello";
    }
    
    @GetMapping("/person")
    Person person() throws RemoteException {return new TestServiceImpl().sendPerson();}
}
  • rmi注册中心
public class RegisterCenter {
    public static void main(String[] args) {
        try {
            // 创建本机上的远程对象注册表Registry的实例,默认端口1099
            LocateRegistry.createRegistry(1099);
            // 创建一个对象
            TestServiceImpl testService = new TestServiceImpl();

            // 把远程对象注册到RMI注册服务器上,testService
            //绑定的URL标准格式为:rmi://host:port/name
            //registry.rebind("testService", testService);
            //Naming.rebind("rmi:localhost:1099/testService",testService);
            Naming.rebind("testService",testService);
            System.out.println("======= 启动RMI服务成功! =======");
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}
  • 服务类
//服务接口

public interface TestService extends Remote {
    public String sendHello() throws RemoteException ;
    public Person sendPerson() throws RemoteException ;
}

// 服务实现类
/*
服务的方法实现类必须直接或简洁继承Remote并抛出RemoteException
 */
public class TestServiceImpl extends UnicastRemoteObject implements TestService {

    public TestServiceImpl() throws RemoteException {
        super();
    }

    public String sendHello (){return "Hello";}

    public Person sendPerson(){return new Person("xiaoxu",22,"北京");}


}
  • 客户端远程调用
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class RmiClient {
    public static void main(String[] args) {
        try {
            //创建RMI注册中心实例(通过socket连接)
            Registry registry = LocateRegistry.getRegistry(1099);
            //远程调用对象的实例化
            Remote testService = registry.lookup("testService");
            //类型强转
            Person person = (Person) testService;
            System.out.println("=======> " + person + " <=======");
        } catch (NotBoundException | RemoteException e) {
            e.printStackTrace();
        }
    }
}

启动主程序和注册中心

在这里插入图片描述
正常访问远程服务器返回参数
在这里插入图片描述

java.rmi.NotBoundException: testService

在这里插入图片描述

如上图所示,报错了,出现该问题可以是服务为注册到注册中心,或者名称错误,检查了好几遍,像如下的格式来回改,还是没成功:

registry.rebind("testService", testService);       

Naming.rebind("rmi:localhost:1099/testService",testService);

最后发现了问题所在,在注册中心上下文脱节了,并没成功注册:

在这里插入图片描述

重构项目,注册中心和注册方法分开,如下:

在这里插入图片描述

将注册中心和注册方法分离,如下:

//注册中心,功能单一生成一个注册中心
public class RegisterCenter {
    public static void main(String[] args) {
        try {
            // 创建本机上的远程对象注册表Registry的实例,默认端口1099
            LocateRegistry.createRegistry(1099);
            System.out.println("======= 启动RMI服务成功! =======");
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}
//注册方法,将类注册到注册中心
public class Register {
    public static void main(String[] args) throws RemoteException {
        //获取注册中心
        Registry registry = LocateRegistry.getRegistry(1099);
        // 创建一个对象
        TestServiceImpl testService = new TestServiceImpl();
        // 把远程对象注册到RMI注册服务器上,testService
        //绑定的URL标准格式为:rmi://host:port/name
        registry.rebind("testService", testService);
       
    }
}

注意注册中心注册的是类,但是类一般都有实现方法,而在其他主机上显然是没有该类的,因为实现类的耦合度高,所以必须使用接口,让实现类实现接口,这样,其他主机上只需要实现接口,就能接受实现类了,也是面向对象多态性的体现。

//客户端远程rmi调用
public class RmiClient {
    public static void main(String[] args) {
        try {
            //创建RMI注册中心实例(通过socket连接)
            Registry registry = LocateRegistry.getRegistry(1099);
            //远程调用对象的实例化
            Remote obj = registry.lookup("testService");
            //Remote obj = Naming.lookup("rmi://:1099/testService");
            //类型强转
            TestService testService = (TestService) obj;
            System.out.println(testService.sendHello());
            //System.out.println("=======> " + testService.sendPerson().toString() + " <=======");
        } catch (NotBoundException | RemoteException e) {
            e.printStackTrace();
        }
    }
}

先启动注册中心,在启动注册任务,最后客户端远程调用:
在这里插入图片描述

上述是通过Registry对象调用的,RMI还提供了该对象的封装类,Naming实现。

注册中心必须和注册任务在一个主机上,这样Java了被注册到注册中心以供RMI注册中心通过协议向外暴露。

注册中心功能单一就是常见注册中心服务器:

LocateRegistry.createRegistry(1099);

注册中心基于自己ip创建,作为服务器,无需指明ip地址。

注册任务程序负责获取创建的注册,并将java类注册到注册中心内:

//获取本机注册中心
Registry registry = LocateRegistry.getRegistry(1099);

//获取指定地址的注册中心
Registry registry1 = LocateRegistry.getRegistry("192.168.223.128",1099);
//注册java类(名称注册默认ip地址)
registry.rebind("testService", testService);

//指定ip地址注册
registry.bind("rmi://192.168.245.1:1099/testService",testService);

Naming实现

Naming.rebind("rmi://192.168.245.1:1099/testService",testService);


Naming.rebind("testService",testService);
Remote obj = Naming.lookup("rmi://192.168.245.1:1099/testService");
Remote obj = Naming.lookup("testService");

参考文章-分布式架构基础:Java RMI详解感谢作者 😃

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/32030.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32实现延时

在STM32单片机中&#xff0c;实现延时一般都是使用定时器&#xff0c;既可以使用Systick定时器&#xff0c;也可以使用常规的定时器。 定时器在设置了定时并开启之后&#xff0c;就会进入自主运行模式&#xff0c;其中&#xff0c;初始化设置这一阶段是由CPU执行相应指令完成的…

ubuntu双系统安装

1. 下载系统 国内镜像 http://mirrors.ustc.edu.cn/ubuntu-releases/2. U盘启动盘 Rufus 软件 制作U盘启动盘 Rufus 链接 https://rufus.en.softonic.com/3. 磁盘中准备一定未分配磁盘 我准备了100G 4. BIOS启动项选择为usb启动&#xff08;每个品牌进BIOS不同&#xff0…

Docker 进入容器和交换文件

1、进入容器 有些时候需要进入容器进行操作&#xff0c;使用 docker exec 命令&#xff0c;这个命令后面可以添加很多参数&#xff0c;我们这里只讲添加 -i 和 -it 参数。 只添加 -i 参数时&#xff0c;由于没有分配伪终端&#xff0c;界面没有我们熟悉的 Linux 命令提示…

Kubernetes 和 Prometheus

资源监控系统是容器编排系统必不可少的组件&#xff0c;也是服务治理的核心之一。而 Prometheus 本质上是一个开源的服务监控系统和时序数据库&#xff0c;是 CNCF 起家的第二个项目&#xff0c;目前已经成为 Kubernetes 生态圈中的监控系统的核心。 Prometheus 的核心组件 Pro…

java学习记录之MySql二

1 mysql回顾 1.1 DDL 数据定义语言&#xff1a;结构  数据库database create database 数据库名称 character set 字符集 [collate 比较]; drop database 数据库名称; alter database 数据库名称 character set 字符集 …;  表 create table 表名(字段描述 , … ); 字段描述…

GD32 SPI 查询方式和DMA方式在全双模式下效率区别

最近在使用SPI的时候&#xff0c;遇到了一些数据传输效率问题&#xff0c;在此记录自己学习过程。SPI的基础知识这里就不在讲述了&#xff0c;直接分析SPI查询方式和DMA方式的效率问题。这里使用的芯片是GD32F303CC。 SPI以查询方式进行全双工通信 1.查询手册&#xff0c;SPI…

Spring Cloud Alibaba-全链路灰度设计

文章目录 灰度发布概念灰度发布架构Spring Cloud Alibaba技术架构下的灰度发布实现基础设计HttpHeader设计 Spring Cloud Gateway改造Spring Cloud Gateway实现灰度发布过滤器 后端服务自定义Spring MVC请求拦截器OpenFeign改造自定义Loadbalancer 测试微服务注册元信息修改自定…

在windows11环境下安装CUDA11.6+Anaconda3+pyToach1.13搭建炼丹炉

0.电脑环境 系统&#xff1a;win11 显卡&#xff1a;NVIDIA GTX1650 还有一个pyCharm&#xff0c;其他也用不到了&#xff0c;需要的文章中会进行说明 1.安装CUDA11.6 目前2023.03出来的pyToach2.0是用不到了&#xff0c;因为最低版本支持CUDA11.7。我的显卡是1650&#xff0c…

阿里巴巴高管换血,吴永明接替张勇

文章目录 经济学人 &#x1f4b0; 第 26 周&#x1fa78; 阿里巴巴高管换血&#xff0c;吴永明接替张勇&#x1f304; 孙正义再出山&#x1f43f;️ 英特尔加码德国&#xff01;投资330亿美元建两座芯片工厂&#xff01;&#x1f30a; 亚马逊被指控强加 Prime 服务✈️ 印度航空…

Jmeter多接口测试之参数传递

目录 前言&#xff1a; 接口示例 正则表达式提取器 正则表达式提取实例 Json提取器 Json提取器实例 前言&#xff1a; 在进行多接口测试时&#xff0c;有些情况下需要将前一个接口返回数据作为后一个接口的参数&#xff0c;以模拟实际场景。JMeter作为一款常用的性能测试…

【EXCEL】如何查找特殊字符 问号‘?’星号 ‘*’

目录 0.环境 1.适用场景 1&#xff09;直接搜索问号的结果&#xff1a; 2&#xff09;修改【查找内容】后&#xff0c;搜索结果变为精准定位&#xff1a; 2.具体做法 0.环境 windows wps&#xff08;或excel&#xff0c;这里试了&#xff0c;此问题wps和excel表格是通用…

中间件解析漏洞

服务器解析漏洞算是历史比较悠久了&#xff0c;但如今依然广泛存在。在此记录汇总一些常见服务器&#xff08;WEB server&#xff09;的解析漏洞&#xff0c;比如IIS6.0、IIS7.5、apache、nginx等 2|0 二、IIS5.x-6.x解析漏洞&#xff08;针对asa/asp/cer&#xff09; 2|11、打…

区块链中怎么惩罚虚假信息的矿工,工作量证明POW,共识算法

目录 区块链中怎么惩罚虚假信息的矿工 工作量证明POW 什么是工作量证明&#xff1f; 现在出现了另一个问题&#xff1a;如果其他人偷看了小明的答案并且抢答了怎么办&#xff1f; 为什么区块可以安全广播&#xff1f; 共识算法 小结 区块链中怎么惩罚虚假信息的矿工 1…

三分钟学习一个python小知识4-----------我的对python中numpy的理解, 我列举了关于numpy常用的10个例子来深入理解numpy

这里写目录标题 1、NumPy是什么2、NumPy的常见应用---必须掌握2.1.创建一个数组2.2.数组的属性2.3.取数组中的元素2.4.数组的运算2.5.数组的转置2.6. 数组的索引和切片2.7. 数组的重塑2.8. 数组的广播2.9. 数组的聚合操作2.10. 数组的排序 总结 1、NumPy是什么 NumPy是专门用于…

Spring MVC简介附入门案例

目录 一、SpringMVC简介 1.1 MVC模型 1.2 SpringMVC 二、SpringMVC入门案例 2.1 创建项目 2.2 引入依赖和tomcat插件 2.3 修改web.xml文件 2.4 新建springmvc.xml文件 2.5 编写控制器 2.6 配置运行方式 2.7 运行测试 三、SpringMVC执行流程 3.1 SpringMVC的组件…

Kangas:计算机视觉中的pandas

Kangas&#xff1a;计算机视觉中的pandas 介绍Kangas的优点 使用Kangas读取CSV文件读取图像文件Kangas DataGrid训练模型 介绍 在计算机视觉领域&#xff0c;Kangas是一种在图像数据处理和分析方面越来越受欢迎的工具之一。就像Pandas改变了数据分析人员处理表格数据的方式一样…

macOS FreeBSD 如何刷新 DNS 缓存

macOS FreeBSD 如何刷新 DNS 缓存 全文&#xff1a;如何刷新 DNS 缓存 (macOS, Linux, Windows) Unix Linux Windows 如何刷新 DNS 缓存 (macOS, FreeBSD, RHEL, CentOS, Debian, Ubuntu, Windows) 请访问原文链接&#xff1a;https://sysin.org/blog/how-to-flush-dns-cach…

AI绘画:切换黑色风格,安装更棒的主题!

从Stable Diffusion 出现的第一天起&#xff0c;我就开始关注这个项目&#xff0c;后来也出过几期教程。 一直以来都是只追求功能实现&#xff0c;不管界面的问题。现在我突然想要换一个帅气的主题了…就是这么突然&#xff01; 默认的白色主题太….普通…既没有设计感啊&…

智能井盖传感器:以科技破解城市顽疾

在城市的道路网络中&#xff0c;井盖扮演着重要的角色&#xff0c;用于覆盖下方的管道和设施&#xff0c;然而&#xff0c;由于井盖的老化、损坏或被盗&#xff0c;常常会导致安全问题的发生&#xff0c;如路面塌陷、行人受伤等。井盖的状态监测和维护一直是城市管理者面临的挑…

社区分享|JumpServer开源堡垒机一直都是我的第一选择

编者注&#xff1a;本文由JumpServer开源堡垒机社区用户James Wei供稿。 “我最开始接触到的堡垒机就是JumpServer&#xff0c;最了解的也是JumpServer&#xff0c;已经完全习惯了JumpServer的使用习惯&#xff0c;这也是我一直选择JumpServer的一个重要原因。” ——JumpSer…