RPC远程调用

news2024/11/28 2:37:54

简介

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详解感谢作者 😃

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用frp工具实现内网穿透以及配置多个ssh和web服务

frp简介 FRP 项目地址 https://github.com/fatedier/frp/blob/master/README_zh.md frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp 协议,为 http 和 https 应用协议提供了额外的能力,且尝试性支持了点对点穿透。 环境准备 ssh连接 1. 需要一台可以直接访问…

简要介绍 | 交叉熵损失:原理和研究现状

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对交叉熵损失进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 注2&#xff1a;"简要介绍"系列的所有创作均使用了AIGC工具辅助 交叉熵损失&#xff1a;原理、研究现状与未来展望 Under…

Web3 是什么?为何应该关注?

当我开始我的职业生涯时&#xff0c;“Web2.0”还是一个热门的新事物。 当我开始我的职业生涯时&#xff0c;正值互联网快速发展的时期&#xff0c;人们谈论的是“Web2.0”&#xff0c;这一概念引发了许多关于用户参与、社交媒体和在线合作的讨论。然而&#xff0c;随着时间的推…

SQL优化--如何分析优化呢?

目录 一个SQL语句执行很慢, 如何分析&#xff1f; ​编辑 重要属性 possible_key key key_len Extra type 面试回答 框架 范例 例&#xff1a; 上面三种查询我们都可以通过执行计划找到查询慢的原因&#xff0c;并且提供解决方案 比如聚合查询可以新增临时表&…

【Leetcode -563.二叉树的坡度 - Nowcoder -KY11.二叉树遍历】

Leetcode Leetcode -563.二叉树的坡度c Leetcode -563.二叉树的坡度 题目&#xff1a;给你一个二叉树的根节点 root &#xff0c;计算并返回 整个树 的坡度 。 一个树的 节点的坡度 定义即为&#xff0c;该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树…

leetcode数据库题第五弹

leetcode数据库题第五弹 1141. 查询近30天活跃用户数1148. 文章浏览 I1158. 市场分析 I1164. 指定日期的产品价格1174. 即时食物配送 II1179. 重新格式化部门表1193. 每月交易 I1204. 最后一个能进入电梯的人1211. 查询结果的质量和占比1251. 平均售价小结 1141. 查询近30天活跃…

chatgpt赋能python:Python打开文件目录:入门指南

Python打开文件目录&#xff1a;入门指南 打开文件目录是编程中常见的操作之一。Python 作为一种优秀的脚本语言&#xff0c;提供了众多的实用方法来操作文件系统。在本文中&#xff0c;我们将介绍如何使用 Python 打开文件目录&#xff0c;同时提供一些对 SEO 优化有帮助的技…

NodeJS 生成APIDOC⑩①

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言API 文档生成工具 APIDOC特点 APIDOC使用步骤0、 运行命令1、 安装插件3、 配置演示4、 ApidocJson配置文件5、效果图 总结 ✨文章有误请指正&#x…

Storm forming 风雨欲来 | 经济学人20230325版社论高质量双语精翻

本期精翻为2023年3月25日《经济学人》周报封面文章&#xff1a;《风雨欲来》&#xff08;Storm forming&#xff09;。 Storm forming 风雨欲来 As video games grow, they are eating the media 随着电子游戏的发展&#xff0c;它们正在蚕食媒体 The games business has lesso…

计算机网络概论

计算机网络概论 组成 客户端&#xff1a;就像蟹堡王的顾客一样。服务端&#xff1a;类似于蟹堡王的分店。路由器&#xff1a;扮演着转发分店的角色。网络协议&#xff1a;像转发表格一样帮助数据在网络中传输。 计算机网络基础 网络组成部分 主机&#xff1a;客户端和服务端…

AVL树原理以及插入代码讲解(插入操作画图~细节)

原理 AVL 树是一种平衡搜索二叉树&#xff0c;得名于其发明者的名字&#xff08; Adelson-Velskii 以及 Landis&#xff09;。&#xff08;可见名字长的好处&#xff0c;命名都能多占一个字母出来&#xff09;。在搜索树的前提下平衡搜索二叉树还定义如下&#xff1a; 左右子…

JVM知识点梳理

什么是JVM&#xff1f; JVM是java虚拟机的缩写 &#xff0c;也是java程式可以实现跨平台的关键。 JVM部分需要知道什么东西&#xff1f; JVM的结构和功能、参数配置、GC回收机制、GC回收器极其优缺点。 JVM结构&#xff08;栈&#xff0c;程序计数器&#xff0c;方法区&#xf…

0009-TIPS-SLAB入门与观察

极简&#xff0c;但是能快速上手 slub算法 这篇文章简洁直观&#xff0c;推荐 linux 内核 内存管理 slub算法 &#xff08;一&#xff09; 原理 感受slub堆漏洞 需要下载 https://github.com/De4dCr0w/green-dill &#xff0c;使用其中的测试程序做实验 UAF 如果看完上面链…

F407/103启动文件and启动过程

STM32 启动文件简介 STM32 启动文件由 ST 官方提供&#xff0c;在官方的固件包里。 startup_stm32f40_41xxx.s 启动文件由汇编编写&#xff0c;是系统上电复位后第一个执行的程序。 启动文件主要做了以下工作&#xff1a; 1 、初始化堆栈指针 SP _initial_sp 2 、初始…

SSM面试题

文章目录 一、Spring1.1 配置一个bean的方式?注解/xml1.2 spring 自动装配 bean 有哪些方式?1.3 spring 常用的注入方式有哪些?1.4 Component和Bean的区别?1.5 spring 事务实现方式有哪些?1.6 spring事务的传播机制?1.7 spring 的事务隔离? 二、SpringMVC2.1 SpringlIvc…

阿里云在国内市场占有率怎么样?

阿里云在国内市场占有率怎么样&#xff1f;   阿里云在国内市场占有率分析   随着互联网的飞速发展&#xff0c;越来越多的企业和个人开始利用云计算服务来满足各种业务需求。作为中国领先的云服务提供商&#xff0c;阿里云自成立以来就受到了广泛关注。本文旨在分析阿里云…

cmake入门(2)

cmake 教程2 demo cmake_minimum_required(VERSION 3.10) project(Tutorial)set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True)add_executable(Tutorial tutorial.cxx)基础 cmake_minimum_required cmake的版本要求 project 项目的名字&#xff0c;同时会生…

ad18学习笔记五:统计焊盘数量(board information)

AD18之后&#xff0c;Altium Designer改动比较大。下面将介绍AD19如何统计焊盘(PAD数量)与SMT贴片数量与插件数量 1&#xff1a; PCB 空白处 -> F11 -> Properties 选项卡 -> Board Information -> Pads 2&#xff1a; Pads 包括 通孔焊盘和贴片焊盘 Vias 包括过孔…

22.小波神经网络时间序列预测交通流量(附matlab程序)

1.简述 学习目标&#xff1a;小波神经网络时间序列预测交通流量 WNN&#xff08;小波神经网络&#xff09;&#xff1a;是在误差反传神经网络拓扑结构的基础上发展而来的网络&#xff0c;与神经网络的结构具有一定的相似&#xff0e;在小波神经网络中&#xff0c;当整体信号…

第十三章 csv模块

1. csv模块介绍 介绍csv 模块前&#xff0c;需要先了解csv 文件&#xff08;.csv 文件格式&#xff09;&#xff0c;csv 文件中的每行代表电子表格中的一行&#xff0c;并用逗号分隔该行中的单元格。 csv 文件可以使用记事本打开&#xff0c;可以使用Excel 另存为.csv 文件格…