小工具      在线工具  汉语词典  dos游戏  css  js  c++  java

简介

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在远程调用的过程中,实际上是在B的服务内部实现了一个浏览器服务来请求服务器返回JSON字符。

RestTemplate

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

HttpClient 是一个用于发送 HTTP 请求的本机 Java 库。 Apache Commons HttpClient是一个基于HttpClient的第三方工具类库。 RestTemplate是Spring框架中封装的HTTP请求操作类。 Feign是一个声明式的Web Service客户端,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:远程方法调用,支持存储在不同地址空间的程序级对象之间进行通信,实现远程对象之间的无缝远程调用。

在这里插入图片描述

前两种实现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();}
}
  • 马绍尔群岛注册中心
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.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详解感谢作者 -

. . .

相关推荐

额外说明

SpringBoot集成logback实现日志输出和存储

1、创建文件 在项目的resources目录下,创建logback-spring.xml文件。 2、完整示例 <?xml version="1.0" encoding="UTF-8"?> <!-- scan:当此属性设置为true时,配置文件如果发生改变

额外说明

判断JS对象和Jquery对象是否存在

一、判断JS对象是否存在: 在JS中获取对象通常通过document.getElementById()和document.getElementsByTagName()函数来获取,但是要是不存在指定的对象浏览器就会报错,因此需要判断一下,下面这个比较简单且

额外说明

阿里p7大手子测试笔记:一线互联网大厂面试问题吃透,巧过面试关

前言 金九银十刚过去,有一部分朋友在这期间肯定经历了一番大厂面试的洗礼,不知道大家是经受住了考验如愿以偿了,还是折戟沉沙无功而返呢? 身边已经有技术大佬顺利通过了阿里P6/P7的面试,在30岁之前成功跳槽进大厂;当然也有朋友没逃过被面试官暴虐的命运……

额外说明

渗透测试-golang语言学习

golang语言学习 环境搭建 win10配置go环境 ubuntu20.04安装golang 介绍 下载 Go 压缩包 调整环境变量 验证 Go 安装过程 环境搭建 win10配置go环境 中文网进行下载 https://studygolang.com

额外说明

csdn保存/发布之后卡住 正在记载中,请稍后(不重新写办法)

QQ 1274510382 Wechat JNZ_aming 商业联盟 QQ群538250800 技术搞事 QQ群599020441 解决方案 QQ群152889761 加入我们 QQ群649347320 共享学习 QQ群674240731 纪年科技am

额外说明

【Java 数据结构 & 算法】宁可累死自己, 也要卷死别人 13 二叉堆

【Java 数据结构 & 算法】⚠️宁可累死自己, 也要卷死别人 13⚠️ 二叉堆 概述 优先队列 二叉堆 二叉堆实现 获取索引 添加元素 siftUp 完整代码 概述 从今天开始, 小白我将带大家开启 Java 数据结构 & 算法的新篇章. 优先队列

额外说明

100天精通Oracle-实战系列 - 总目录

100天精通Oracle-实战系列 总目录 一、Oracle 入门安装 二、Oracle RMAN 备份恢复 三、Oracle 数据泵系列 四、Oracle RAC 高可用 五、Active DataGuard 容灾 六、Oracle 分区表系列 七、O

额外说明

Keras深度学习实战(22)——生成对抗网络详解与实现

Keras深度学习实战(22)——生成对抗网络详解与实现 0. 前言 1. 生成对抗网络原理 2. 模型分析 3. 利用生成对抗网络生成手写数字图像 小结 系列链接 0. 前言 生成对抗网络 (Generative Adversarial Network

额外说明

【C语言】C语言标准头文件

文章目录 前言 一、stdarg.h 二、stdbool.h 三、time.h 前言 为什么要学标准头文件:因为他是可以跨平台的,每个编译器都支持,所以我们需要学习。本节课讲的是<stdarg.h>/<stdbool.h> <time.h> 提示:以下是

额外说明

【Python】报错:You should consider upgrading via the 'python -m pip install --upgrade pip' command.

目录 一、报错情况 二、报错原因 三、报错解决 一、报错情况 WARNING: You are using pip version 19.1.1, however version 19.3.1 is available. You should consi

ads via 小工具