小工具      在线工具  汉语词典  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详解感谢作者 -

. . .

相关推荐

额外说明

Abaqus软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载   一、软件简介 Abaqus是一款专业的有限元分析软件,广泛应用于工程领域,特别是机械、汽车、航空航天、材料科学等领域。它具有强大的有限元分析功能,可以模拟各种复杂的物理和力学问题,为工程师提供可靠的仿真和分析工具。

额外说明

C#WPF开发环境配置

1.SQL2014版本端口号修改,不能与2015版本冲突,打开SQL2014配置管理器更改客户端端口号。 2.选择性修改网络端口号。 3.安装SQL2015, 4.勾选需要功能。 5. 6.数据库命名,首先勾选默认实例,获取到名字再勾选命名实例修改或添加

额外说明

【Linux基础篇三】为什么说在Linux世界里,一切皆文件?

-作者简介:大家好,我是卷心菜~~,在校大二学生一枚,Java领域新星创作者。 -个人主页:卷心菜的CSDN博客 -系列专栏:本文写在Linux专栏:Linux学习专栏 -如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步- -如果感觉博主的文

额外说明

Oracle 数据库巡检,需要关注哪些点?(一些个人见解)

目录 - 前言 - 一、⭐️ 主机层面 ⭐️ 1、- 主机版本和Oracle版本 2、- 主机硬件资源 3、- 计划任务 crontab 4、- 检查 Hosts 文件和网络配置 5、- 检查系统参数文件 6、- 检查 rc.local 文件 7、- 环

额外说明

HNU-操作系统OS-实验Lab1

OS_Lab1_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf (学号 202108010XXX) 为了实现 lab1 的目标,lab1 提供了 6 个基本练习和 1 个扩展练习,要求完成实验报告。 对实验报

额外说明

Django讲课笔记06:搭建项目开发环境

文章目录 零、本讲学习目标 一、课程导入 二、新课讲授 (一)创建Django项目 - babies (二)新建应用 - index (三)创建应用 - commodity (四)创建应用 - shopper (五)项目目录结构图 1、babies文件夹

额外说明

Java中的接口详解

概述 接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。 接口的定义,它与定

额外说明

常见Dos命令、Java历史、Java跨平台、配置Path环境变量、第一个HelloWorld例子

文章目录 常见Dos命令、Java历史、Java跨平台 计算机基础 计算机 硬件和软件 硬件 软件 人机交互的方式: 常见的dos命令 Java简介 Java语言重要特性之跨平台 跨平台 Java的跨平台 Java虚拟机(JVM) Java的三大平台 环

额外说明

mfc110fra.dll文件丢失找不到如何解决?

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或者损坏了,这时你只需下载这个mfc110fra.dll文件进行安装(前提是找到适合的版本)

额外说明

软件或游戏出现缺少xactengine3_0.dll解决方法

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或者损坏了,这时你只需下载这个xactengine3_0.dll文件进行安装(前提是找到适合

ads via 小工具