Java中的远程方法调用——RPC详解

1. 什么是RPC?

RPC基础介绍

        Java中的远程方法调用(Remote Procedure Call,RPC)是一种允许一个程序调用另一台计算机上方法的技术,就像在本地一样。RPC的核心思想是简化分布式计算,让我们可以跨网络调用远程服务,而不需要关心底层网络细节。简单来说,在它调用另一台计算机上的方法的技术时,效果类似于调用本地方法。用一个例子来说明:

        假设我们有一个客户端程序,它需要访问一个服务器上的资源,比如用户信息。使用RPC,客户端就可以像调用自己机器上的方法一样,远程调用服务器上提供的“获取用户信息”的方法。在客户端的角度,它并不知道这个方法实际在另一台机器上执行,一切都像是本地操作。

RPC背后的核心目标

        RPC的目标是让分布式系统中的方法调用变得简单。通过RPC,开发者不必关心网络传输、数据格式转换等细节,只需要按照调用本地方法的方式来调用远程方法。这种透明性为分布式应用程序开发带来了极大的便利。

        RPC实现了“本地调用”的效果,但它实际是在网络上完成了远程方法调用。

2. 为什么使用RPC?

        在分布式系统或微服务架构中,应用程序通常被分解为多个独立的服务,每个服务都可能运行在不同的服务器上。为了实现这些服务之间的通信,我们可以使用RPC。以下是使用RPC的几个主要原因:

1. 解耦服务,提升灵活性

  • RPC允许不同的服务在不同的机器上独立运行。每个服务都可以独立开发、部署和扩展。
  • 使用RPC后,服务之间只通过方法调用进行交互,而不需要知道彼此的内部实现。这样,服务的实现方式可以自由改变,而不会影响到依赖它的其他服务。

2. 简化网络通信

  • 在没有RPC的情况下,我们需要手动处理网络通信,比如套接字编程、序列化/反序列化数据、处理网络延迟等。
  • RPC将这些网络细节都隐藏在底层,使开发者可以像调用本地方法一样简单地调用远程服务,降低了开发复杂度。

3. 提高开发效率

  • 通过RPC,开发者不需要学习复杂的网络编程知识。这对跨团队协作、快速开发原型等都有帮助,极大地提升了开发效率。

4. 便于跨语言、跨平台调用

  • 现代RPC协议(例如gRPC)支持不同的编程语言,能使Java客户端调用Python或Go编写的服务。
  • 这让服务能够运行在不同平台上,支持多样化的技术栈,给系统设计带来了更大灵活性。

        RPC为分布式系统提供了强大的跨服务、跨语言通信能力,简化了复杂的网络编程工作,使得多服务协作变得更加自然。

3. RPC的基本原理

        RPC的工作过程看似简单,但它其实包含了多个步骤。在概念上,可以将RPC分为客户端请求服务器响应两个部分,我们先简要了解流程,再详细拆解每一步的工作机制。

RPC的基本流程

  1. 客户端请求:客户端调用一个“本地代理方法”,这个方法会将请求传递给远程服务器。
  2. 网络传输:客户端将请求的数据通过网络发送到远程服务器。
  3. 服务器处理:服务器接收到请求,找到相应的服务方法,执行并将结果返回。
  4. 结果返回:服务器将结果传回客户端,客户端接收并使用结果,完成调用。

关键组成部分

要实现这一流程,RPC通常需要以下几个关键组成部分:

  • 客户端代理(Client Stub):客户端的“本地代理方法”,它伪装成一个本地方法调用,背后却是将请求打包并发送给服务器。
  • 服务器代理(Server Stub):服务器上的代理,它负责接收客户端请求,解包请求参数并调用实际的远程方法。
  • 网络传输:负责在客户端和服务器之间传输数据,通常采用TCP/IP协议。
  • 序列化与反序列化:将方法参数转换成可以传输的格式(比如JSON、XML等),并在接收到数据后反向还原成对象。

流程拆解

我们再来看一下具体每一步发生了什么:

  1. 方法调用(客户端代理)

    • 客户端调用一个本地的“代理方法”,这个方法看似本地,但会触发远程调用。
    • 代理会把调用的方法名称参数打包,并交给下一个环节(序列化)。
  2. 序列化(客户端代理)

    • 代理将方法名称和参数序列化为一种通用的格式(如JSON、XML),方便跨网络传输。
    • 序列化后的数据包被发送到服务器。
  3. 数据传输(网络传输)

    • 序列化数据包通过网络(一般是TCP/IP)传输到目标服务器。
    • 这部分由RPC框架负责封装,使调用方无须处理底层网络操作。
  4. 解包与方法执行(服务器代理)

    • 服务器代理接收到数据包后,先进行反序列化,将其还原为方法名称和参数。
    • 然后,代理找到相应的方法,并传入参数执行。
  5. 返回结果

    • 方法执行完毕后,结果数据被序列化,打包并通过网络返回给客户端。
    • 客户端收到结果后,代理将数据反序列化,还原成方法调用结果,调用完成。

        RPC通过客户端代理、服务器代理和网络传输的配合,模仿了“本地调用”的效果。每一个步骤背后都由RPC框架完成复杂的底层工作,让开发者无需关注复杂的网络细节。

4. Java中的RPC实现方式

RMI(Remote Method Invocation)

简介

        RMI是Java内置的RPC实现,它允许Java应用程序之间调用远程对象,类似于本地调用。RMI只支持Java语言,因此在Java应用之间通信时相对方便,但只能用于Java环境,限制了跨语言调用。

特点

  • 单一语言:只支持Java,无法在其他语言环境中使用。
  • 序列化机制:基于Java自带的序列化机制,传输Java对象较为方便,但序列化性能相对较慢。
  • 简单实现:因为是Java自带的API,开发和部署相对简单,不需要额外的第三方依赖。
  • 同步调用:通常采用同步的调用方式,不适合高并发环境。

使用场景

        RMI适用于小型Java系统之间的简单远程调用,例如在单一Java环境中做分布式处理、调用Java应用中的服务等。但是,由于其性能和跨语言局限性,它并不适合复杂的大规模微服务架构。

Hessian

简介

        Hessian是一个轻量级的二进制RPC协议,支持Java与多种其他语言间的跨语言调用。Hessian使用二进制格式来传输数据,相较于文本协议(如JSON、XML)具有更好的传输性能。

特点

  • 跨语言支持:Hessian提供多种语言实现,支持Java与Python、PHP等其他语言之间的通信。
  • 二进制序列化:采用二进制格式,传输数据体积小,序列化与反序列化性能较高。
  • 轻量级:Hessian实现较为简单,适合快速集成到应用中。
  • 较好的兼容性:不依赖复杂的第三方组件,适合与微服务架构结合。

使用场景

        Hessian适合跨语言、轻量级分布式系统,尤其是在服务间传递大量数据时,Hessian的二进制传输可以减少网络开销。常用于内部微服务通信,如Java与其他语言服务的接口调用,适合数据传输量较大的应用场景。

Dubbo

简介

        Dubbo是阿里巴巴开源的高性能Java RPC框架,提供了更加完整的分布式服务治理功能。Dubbo不仅仅是RPC,还支持服务注册与发现、负载均衡、容错机制、监控等特性,适合构建复杂的微服务架构。

特点

  • 支持服务治理:内置服务注册、发现、负载均衡、容错处理等功能,支持多种注册中心(如Zookeeper、Nacos)。
  • 高性能:Dubbo采用了高效的网络协议和线程模型,能支持高并发和低延迟。
  • 丰富的协议支持:Dubbo支持多种传输协议(如Dubbo协议、RMI、Hessian等),开发者可以根据需求选择。
  • 支持异步调用:Dubbo支持异步调用,能够处理高并发场景。

使用场景

        Dubbo适合大型微服务架构和分布式系统,特别是需要服务治理和负载均衡的复杂系统。它广泛应用于企业级分布式应用,例如电商系统的订单服务、支付服务等,支持服务的快速扩展和高性能需求。

三者对比与选择

特性RMIHessianDubbo
语言支持仅支持Java支持Java和其他语言主要支持Java
序列化方式Java内置序列化二进制序列化支持多种协议和序列化
性能较低较高高(适合高并发)
服务治理有,支持注册、发现、负载均衡等
适用场景简单的Java远程调用跨语言轻量级RPC大型分布式系统、微服务架构
  • RMI:适合简单、轻量的Java系统间调用,不需要复杂的服务治理。
  • Hessian:适合跨语言、轻量级服务调用,有较好的传输效率,适用于小型分布式系统。
  • Dubbo:适合需要服务治理的大规模Java微服务架构,性能高、功能丰富,是企业级分布式系统的优选。

        如果对多语言支持需求高,选Hessian;如果是单一Java微服务场景,选Dubbo。

5. RMIHessianDubbo的实现详解

RMI(Remote Method Invocation)

        RMI是Java内置的RPC实现方式,适合Java-to-Java的远程调用。在RMI中,服务器端的远程对象可以被客户端远程调用,像在本地调用一样。下面,我们通过四个步骤来实现RMI的基本过程。

实现步骤

  1. 定义远程接口:指定哪些方法可以被远程调用。
  2. 实现远程接口:服务器端实现远程接口中的方法。
  3. 启动RMI服务器:将远程对象注册到RMI注册表中,以便客户端查找。
  4. 客户端调用远程方法:客户端通过RMI注册表查找远程对象,并调用方法。

代码示例

Step 1: 定义远程接口

        首先,定义一个远程接口,继承java.rmi.Remote,并声明抛出RemoteException。例如,我们创建一个HelloService接口。

import java.rmi.Remote;
import java.rmi.RemoteException;public interface HelloService extends Remote {String sayHello(String name) throws RemoteException;
}

Step 2: 实现远程接口

在服务器端,我们创建HelloService的实现类,并实现其中的方法。

import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;public class HelloServiceImpl extends UnicastRemoteObject implements HelloService {protected HelloServiceImpl() throws RemoteException {super();}@Overridepublic String sayHello(String name) throws RemoteException {return "Hello, " + name + "!";}
}

Step 3: 启动RMI服务器

将实现类实例化,并将其注册到RMI注册表中。这样,客户端可以通过注册表找到这个远程对象。

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RMIServer {public static void main(String[] args) {try {HelloService service = new HelloServiceImpl();Registry registry = LocateRegistry.createRegistry(1099);registry.bind("HelloService", service);System.out.println("RMI server is running...");} catch (Exception e) {e.printStackTrace();}}
}

Step 4: 客户端调用远程方法

在客户端,连接到RMI注册表,查找远程对象,并调用方法。

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RMIClient {public static void main(String[] args) {try {Registry registry = LocateRegistry.getRegistry("localhost", 1099);HelloService service = (HelloService) registry.lookup("HelloService");String response = service.sayHello("Alice");System.out.println("Response from server: " + response);} catch (Exception e) {e.printStackTrace();}}
}

Hessian

        Hessian是一个轻量级的二进制协议,支持跨语言调用,适用于Java与其他语言间的通信。Hessian实现简单,传输数据体积小,序列化效率高。以下是Hessian的服务端与客户端实现步骤。

实现步骤

  1. 添加Hessian依赖:引入Maven依赖。
  2. 定义远程接口和实现:编写接口和实现类。
  3. 配置HessianServlet:暴露服务接口。
  4. 客户端调用远程服务:客户端通过Hessian代理调用服务。

代码示例

Step 1: 添加Hessian依赖

在Maven项目的pom.xml中加入以下依赖。

<dependency><groupId>com.caucho</groupId><artifactId>hessian</artifactId><version>4.0.63</version>
</dependency>

Step 2: 定义远程接口和实现

定义远程接口HelloService并实现它:

public interface HelloService {String sayHello(String name);
}
public class HelloServiceImpl implements HelloService {@Overridepublic String sayHello(String name) {return "Hello, " + name + "!";}
}

Step 3: 配置HessianServlet

在Web应用中使用HessianServlet,将接口暴露为远程服务。

<!-- web.xml -->
<servlet><servlet-name>helloService</servlet-name><servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class><init-param><param-name>home-api</param-name><param-value>com.example.HelloService</param-value></init-param><init-param><param-name>home-class</param-name><param-value>com.example.HelloServiceImpl</param-value></init-param>
</servlet><servlet-mapping><servlet-name>helloService</servlet-name><url-pattern>/helloService</url-pattern>
</servlet-mapping>

Step 4: 客户端调用远程服务

客户端通过Hessian的HessianProxyFactory代理远程服务。

import com.caucho.hessian.client.HessianProxyFactory;public class HessianClient {public static void main(String[] args) {try {String url = "http://localhost:8080/helloService";HessianProxyFactory factory = new HessianProxyFactory();HelloService service = (HelloService) factory.create(HelloService.class, url);String result = service.sayHello("Alice");System.out.println(result);} catch (Exception e) {e.printStackTrace();}}
}

Dubbo

        Dubbo是一个高性能Java RPC框架,广泛应用于企业级微服务架构中。Dubbo提供了服务治理功能,支持负载均衡、服务发现、熔断等,适合大规模分布式系统。

实现步骤

  1. 添加Dubbo和Zookeeper依赖:引入Dubbo和Zookeeper依赖。
  2. 定义远程接口和实现:编写服务接口和实现类。
  3. 配置Dubbo注册中心和服务:使用Zookeeper等注册中心管理服务。
  4. 客户端调用远程服务:通过Dubbo动态代理调用服务。

代码示例

Step 1: 添加Dubbo和Zookeeper依赖

在Maven项目的pom.xml中加入以下依赖:

<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>2.7.8</version>
</dependency>
<dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.5.7</version>
</dependency>

Step 2: 定义远程接口和实现

和前面类似,定义HelloService接口和实现类。

public interface HelloService {String sayHello(String name);
}
import org.apache.dubbo.config.annotation.Service;@Service // Dubbo的Service注解
public class HelloServiceImpl implements HelloService {@Overridepublic String sayHello(String name) {return "Hello, " + name + "!";}
}

Step 3: 配置Dubbo注册中心和服务

Dubbo支持服务注册与发现,通常使用Zookeeper作为注册中心。

<!-- Dubbo配置 -->
<dubbo:application name="HelloServiceProvider"/>
<dubbo:registry address="zookeeper://localhost:2181"/>
<dubbo:protocol name="dubbo" port="20880"/>
<dubbo:service interface="com.example.HelloService" ref="helloService"/>

Step 4: 客户端调用远程服务

客户端通过Dubbo的动态代理机制来调用远程服务。

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;public class DubboClient {public static void main(String[] args) {ReferenceConfig<HelloService> reference = new ReferenceConfig<>();reference.setApplication(new ApplicationConfig("HelloServiceConsumer"));reference.setRegistry(new RegistryConfig("zookeeper://localhost:2181"));reference.setInterface(HelloService.class);HelloService service = reference.get();String result = service.sayHello("Alice");System.out.println(result);}
}

总结

  1. RMI适合简单Java-to-Java调用。
  2. Hessian支持跨语言、轻量级的远程调用。
  3. Dubbo适合大规模分布式系统,提供服务治理功能。

每种实现方式都有独特的使用场景,选择时可根据系统需求灵活决定。

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

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

相关文章

Git详细使用

本地项目托管到码云中教程 1. 使用git init 命令&#xff0c;git init命令用于在目录中创建新的 Git 仓库。 在目录中执行git init就可以创建一个 Git 仓库了。 2. 使用git status命令查看未提交的文件 3. 使用git add . 命令将所有文件添加到暂存区 4. 使用git commit -m &qu…

开源办公软件 ONLYOFFICE 深入探索

文章目录 引言1. ONLYOFFICE 创建的背景1. 1 ONLYOFFICE 项目启动1. 2 ONLYOFFICE 的发展历程 2. 核心功能介绍2. 1 桌面编辑器2. 1. 1 文档2. 1. 2 表格2. 1. 3 幻灯片 2. 2 协作空间2. 3 文档编辑器 - 本地部署版 3. 技术介绍4. 安装5. 优势与挑战6. 个人体验7. 强大但不止于…

Day95 Docker

Docker的使用 1、Docker是什么 docker是一个用来管理镜像的容器 容器(container)&#xff1a;可以装东西 镜像( image )&#xff1a;所谓的镜像&#xff0c;你可以认为就是一个虚拟机 虚拟机&#xff1a;用软件代理硬件来模拟整个计算机的这样一套软件就成为 虚拟机 镜像说白了…

WPF中如何简单的使用CommunityToolkit.Mvvm创建一个项目并进行 增删改查

目录 开始前准备的数据库dbblog如下&#xff1a; 第一步&#xff1a;创建项目后下载四个NuGet程序包 第二步&#xff1a;删除原本的MainWindow.XAML文件 并创建如下的目录结构 然后在View文件夹下面创建Login.XAML和Main.XAML 并且在App.XAML中将启动项改为Login.XA…

多模态PaliGemma——Google推出的基于SigLIP和Gemma的视觉语言模型

前言 本文怎么来的呢&#xff1f;其实很简单&#xff0c;源于上一篇文章《π0——用于通用机器人控制的流匹配VLA模型&#xff1a;一套框架控制7种机械臂(改造了PaliGemma和ACT的3B模型)》中的π0用到了PaliGemma 故本文便来解读下这个PaliGemma 第一部分 PaliGemma 1.1 Pal…

微服务day03

导入黑马商城项目 创建Mysql服务 由于已有相关项目则要关闭DockerComponent中的已开启的项目 [rootserver02 ~]# docker compose down WARN[0000] /root/docker-compose.yml: version is obsolete [] Running 4/4✔ Container nginx Removed …

IAPP仿源码大师主界面UI

仿源码大师首页主界面的布局 首页&#xff0c;分类&#xff0c;需求&#xff0c;我的 就只有这几个界面内容而已 资源静态 没有任何动画和功能 纯UI布局 纯UI布局 https://pan.baidu.com/s/1Hc5nWQCZ_ckQlXXV82OYpA?pwd7826 https://caiyun.139.com/m/i?2i2MoYbkdze41 来源…

mmpretrainmmdetection环境配置

mmpretrain&mmdetection环境配置 适用于cuda11.3torch12.1的mmpretrain&mmdetection环境配置&#xff1a; 第一步&#xff1a;根据官网说明&#xff0c;找到对应cuda版本的torch&#xff0c;安装好torch&#xff1a; pip install torch1.12.1cu113 torchvision0.13.…

【数据湖及大数据方案】数据湖建设方案|数据源|数据流|元数据|数据仓库|指标池|数据清洗

建设大数据湖一体化平台旨在应对数据分散、管理混乱及利用低效等挑战。通过集中存储与管理跨平台数据&#xff0c;打破信息孤岛&#xff0c;实现数据资产的高效整合与利用。该平台强化数据标准、质量控制、开发运维及安全保障&#xff0c;提升数据治理成熟度。此外&#xff0c;…

搭建企业私有云 只需一台设备 融合计算、存储与K8s

Infortrend老牌存储厂商推出 KS 企业私有云产品&#xff0c;将计算节点、存储与Kubernetes整合在一套系统中&#xff0c;为企业提供高效稳定的专属本地私有云平台。 KS 同时内置 Kubernetes 平台和虚拟机管理程序&#xff0c;既能运行云原生容器化应用程序&#xff0c;例如大数…

[Redis] Redis主从复制模式

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

计算机毕业设计Hadoop+PySpark深度学习游戏推荐系统 游戏可视化 游戏数据分析 游戏爬虫 Scrapy 机器学习 人工智能 大数据毕设

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

iOS SmartCodable 替换 HandyJSON 适配记录

前言 HandyJSON群里说建议不要再使用HandyJSON&#xff0c;我最终选择了SmartCodable 来替换&#xff0c;原因如下&#xff1a; 首先按照 SmartCodable 官方教程替换 大概要替换的内容如图&#xff1a; 详细的替换教程请前往&#xff1a;使用SmartCodable 平替 HandyJSON …

16、论文阅读:Mamba YOLO:用于目标检测的基于 SSM 的 YOLO

Mamba YOLO: SSMs-Based YOLO For Object Detection 总结前言感受野为什么Transformer 的结构被引入&#xff0c;显著扩展了模型的感受野&#xff1f;状态空间模型SSM 介绍相关工作实时目标检测端到端目标检测器视觉状态空间模型 方法预处理整体架构ODSS BlockLocalSpatial Blo…

微信小程序 uniapp+vue老年人身体监测系统 acyux

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 过此方式促进老年人辅助程序信息流动和数据传输效率&#xff0c;提供一个内容丰富、功能多样、易于操作的老年人辅助程序…

Intellij IDE报错:[Information:java:javacTask:源发行版8需要目标发行版1.8]

Intellij IDE报错:[Information:java:javacTask:源发行版8需要目标发行版1.8] 处理方法 File->Settings->Build,execution,Deployment->Compiler->Java Compiler 进入该目录下&#xff0c;修改Per-module bytecode version&#xff0c;将该项目修改为8 合理的创…

Pr 沉浸式视频 - 自动 VR 属性

自动 VR 属性 Auto VR Properties是所有 VR 视频效果和视频过渡效果的通用选项。 默认勾选。此选项使效果自动适应 VR 素材的属性&#xff0c;确保在 360 全景环境中无缝显示。 当处理 VR/360 素材时&#xff0c;保持勾选以避免接缝。 当处理非 VR 素材或需要手动设置 VR 属性时…

[项目] C++基于多设计模式下的同步异步日志系统

[项目] C基于多设计模式下的同步&异步日志系统 文章目录 [项目] C基于多设计模式下的同步&异步日志系统日志系统1、项目介绍2、开发环境3、核心技术4、日志系统介绍4.1 日志系统的价值4.2 日志系统技术实现4.2.1 同步写日志4.2.2 异步写日志 5、相关技术知识5.1 不定参…

ubuntu下使用pocketsphinx进行语音识别

文章目录 前言一、pocketsphinx的介绍二、ubuntu下编译三、使用示例1.模型选择2.代码示例3.自定义字典 四、交叉编译总结 前言 由于工作需要语音识别的功能&#xff0c;环境是在linux arm版上&#xff0c;所以想先在ubuntu上跑起来看一看&#xff0c;就找了一下语音识别的开源…

C语言原码、反码和补码的详解

C语言原码、反码和补码的详解 放在最前面的1、前言正数的原码、反码和补码负数的原码、反码和补码 2、整数的原码&#xff08;2.1&#xff09;原码的定义&#xff08;2.2&#xff09;计算原码 3、整数的反码&#xff08;3.1&#xff09;反码的定义&#xff08;3.2&#xff09;计…