当前位置: 首页 > news >正文

Spring Boot与gRPC的完美融合:构建高效用户服务与订单服务通信

gRPC 是一种由 Google 开发的高性能、开源的远程过程调用(Remote Procedure Call, RPC)框架。它允许在不同的计算机系统或进程之间进行通信,使得分布式系统和微服务架构中的服务之间能够轻松地相互调用方法。gRPC 基于 HTTP/2 协议,并使用 Protocol Buffers(Protobuf)作为其接口定义语言和序列化格式。

gRPC 的主要特点和优点:

  1. 跨语言支持
    gRPC 支持多种编程语言,包括 C++, Java, Python, Go, C#, Node.js 等,因此不同语言编写的服务之间可以无缝通信。

  2. 高性能
    gRPC 使用 HTTP/2 协议,这意味着它支持双向流、多路复用和头部压缩,能更高效地利用网络资源,降低延迟。

  3. 协议定义
    gRPC 使用 Protocol Buffers 作为其接口定义语言(IDL)。开发者通过定义 .proto 文件,描述服务和消息结构,gRPC 工具可以自动生成对应语言的客户端和服务器端代码。

  4. 简单易用
    gRPC 提供了一套简洁的 API,开发者可以轻松创建和调用远程服务,就像调用本地方法一样。

  5. 双向流和流控
    gRPC 不仅支持传统的一次性请求-响应模型,还支持双向流,使得客户端和服务器之间可以发送多个消息,并且这些消息可以并行地传输和处理。

  6. 安全性
    gRPC 原生支持 SSL/TLS,可以很容易地实现安全的通信。

gRPC 的应用场景:

  1. 微服务架构
    在微服务架构中,服务之间需要进行大量的通信,gRPC 提供了高效、跨语言的解决方案,适用于需要低延迟和高吞吐量的应用。

  2. 分布式系统
    在分布式系统中,多个节点之间可能需要频繁通信,gRPC 的高性能和双向流支持非常适合这种场景。

  3. 实时通信
    gRPC 的双向流特性使其非常适合需要实时数据交换的应用,例如实时聊天、视频流、物联网(IoT)应用等。

  4. 跨平台服务
    由于 gRPC 支持多种语言和平台,它非常适合构建跨平台的分布式服务。

总结来说,gRPC 是一种高效、灵活的远程调用框架,特别适合需要跨语言、高性能通信的分布式系统和微服务架构。

一个常见的 gRPC 使用实例是在微服务架构中,尤其是像 Uber 这样的公司,它们拥有多个微服务,需要在不同的服务之间进行高效、低延迟的通信。

需求:用户服务和订单服务的通信

假设有一个电商平台,它的系统由多个微服务组成,其中包括:

  1. 用户服务(User Service):管理用户信息,如注册、登录、个人资料等。
  2. 订单服务(Order Service):处理用户的订单信息,如创建订单、查询订单状态等。
  3. grpc-api:将 gRPC 的 Protobuf 定义提取到一个独立的 grpc-api 模块中,其他微服务(如用户服务和订单服务)可以引用该模块,共享 gRPC 定义和生成的代码。

用户在下订单时,订单服务需要验证用户的身份,并获取用户的相关信息(如地址、支付方式等)。在这种情况下,订单服务需要调用用户服务来获取这些信息。

模块的目录结构

├─grpc-api
│  └─src
│      └─main
│          ├─java
│          │  └─com
│          │      └─song
│          │          └─api
│          ├─proto
│          └─resources
├─grpc-order
│  └─src
│      └─main
│          ├─java
│          │  └─com
│          │      └─song
│          │          ├─service
│          │          └─web
│          └─resources
└─grpc-user└─src└─main├─java│  └─com│      └─song│          └─service└─resources

1. 创建 grpc-api 模块

创建一个 Maven 项目 grpc-api,用于存放 .proto 文件和生成的 gRPC Java 代码。这个模块将被其他服务(如用户服务和订单服务)依赖。

2. 在 grpc-api 模块中定义 .proto 文件

grpc-api 模块的 src/main/proto/ 目录下创建 .proto 文件,例如:

syntax = "proto3";package com.song.api;
// 创建一个rpc 服务
service UserService {rpc GetUserInfo (GetUserInfoRequest) returns (GetUserInfoResponse);
}
//方法的入参请求对象与入参 。参数必须有唯一标识并还是有顺序的
message GetUserInfoRequest {string user_id = 1;
}
//方法的响应请求对象与响应参数 。参数必须有唯一标识并还是有顺序的
message GetUserInfoResponse {string name = 1;string email = 2;string address = 3;
}

3. 配置 grpc-api 模块的 pom.xml

grpc-api 模块的 pom.xml 中,配置 gRPC 和 Protobuf 相关的依赖和插件,以便自动生成 gRPC 代码。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>yqmm-grpc</artifactId><groupId>com.song</groupId><version>1.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>grpc-api</artifactId><description>grpc公共api提取</description><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><grpc-version>1.40.1</grpc-version><protobuf-version>3.21.9</protobuf-version></properties><dependencies><!-- gRPC 依赖 --><dependency><groupId>io.grpc</groupId><artifactId>grpc-all</artifactId><version>${grpc-version}</version></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf-version}</version></dependency><!-- https://mvnrepository.com/artifact/com.google.protobuf/protoc --><dependency><groupId>com.google.protobuf</groupId><artifactId>protoc</artifactId><version>${protobuf-version}</version><type>pom</type></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.6.1</version><configuration><protocArtifact>com.google.protobuf:protoc:3.19.1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.50.2:exe:${os.detected.classifier}</pluginArtifact><!-- 设置输出目录 --><outputDirectory>${project.basedir}/src/main/java</outputDirectory><!-- 设置proto文件所在目录 --><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><!-- 是否清除输出目录 --><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><layout>NONE</layout><skip>true</skip>           <!--    自己打出的包也能用 ,就是打出的包不包含BOOT-INF目录        --></configuration></plugin></plugins></build></project>

4. 生成 gRPC 代码

grpc-api 模块根目录下运行以下命令来生成 gRPC 代码:

mvn compile

或者
在这里插入图片描述

编译后,Protobuf 文件会被编译成 Java 类,生成的 gRPC 类会存放在 target/generated-sources/protobuf 目录中,并打包到 grpc-api 的 jar 文件中。

5. 创建用户服务模块

创建一个新的 Maven 模块(如 grpc-user),该模块将实现 gRPC 服务端,使用 grpc-api 共享的 gRPC 定义。

用户服务模块的 pom.xml

grpc-user 模块的 pom.xml 中,添加对 grpc-api 的依赖以及 gRPC 相关的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>yqmm-grpc</artifactId><groupId>com.song</groupId><version>1.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>grpc-user</artifactId><description>服务端</description><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><grpc-service-version>2.14.0.RELEASE</grpc-service-version></properties><dependencies><dependency><groupId>com.song</groupId><artifactId>grpc-api</artifactId><version>1.1-SNAPSHOT</version></dependency>
<!--        服务端--><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>${grpc-service-version}</version></dependency></dependencies>
</project>
实现 gRPC 服务

grpc-user 模块中,基于 grpc-api 中的生成代码实现 gRPC 服务端:

/*** 自定义数据查询  提供给客户端数据*/
@GrpcService
@Slf4j
public class UserService extends UserServiceGrpc.UserServiceImplBase{@Overridepublic void getUserInfo(User.GetUserInfoRequest request,StreamObserver<User.GetUserInfoResponse> responseObserver) {log.info("客户端发来的请求参数UserId>>>>>>>{}",request.getUserId());// todo 客户端发来的请求参数UserId 查询数据库db// todo 模拟db返回出来的用户数据User.GetUserInfoResponse response = User.GetUserInfoResponse.newBuilder().setName("song-name").setEmail("song.com").setAddress("北京").build();responseObserver.onNext(response);responseObserver.onCompleted();}
}

配置:application.yml

grpc:server:port: 9190  # 设置 gRPC 服务器端口
server:port: 10002spring:application:name: grpc-user

启动类


@SpringBootApplication
public class UserApplication {public static void main(String[] args) {SpringApplication.run(UserApplication.class, args);}
}

6. 创建订单服务模块

同样,创建订单服务模块(如 grpc-order),该模块将作为 gRPC 客户端调用用户服务。

订单服务模块的 pom.xml

grpc-order 模块的 pom.xml 中,添加对 grpc-api 模块的依赖以及 gRPC 相关的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>yqmm-grpc</artifactId><groupId>com.song</groupId><version>1.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>grpc-order</artifactId><description>客户端</description><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><grpc-client-version>2.14.0.RELEASE</grpc-client-version></properties><dependencies>
<!--        客户端--><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>${grpc-client-version}</version></dependency>
<!--        grpc-api --><dependency><groupId>com.song</groupId><artifactId>grpc-api</artifactId><version>1.1-SNAPSHOT</version></dependency></dependencies>
</project>
调用 gRPC 客户端

grpc-order 中,通过 gRPC 客户端调用用户服务获取用户信息:

@Service
public class UserClient {@GrpcClient("grpc-user") // yml里面指定访问服务端地址private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;public User.GetUserInfoResponse getUserInfo(String userId) {User.GetUserInfoRequest request = User.GetUserInfoRequest.newBuilder().setUserId(userId).build();return userServiceBlockingStub.getUserInfo(request);}
}
订单服务控制调用层

在订单服务中,可以使用 UserServiceClient 来获取用户信息并处理订单:

@RestController
public class OrderController {private final UserClient userClient;public OrderController(UserClient userClient) {this.userClient = userClient;}@GetMapping("/order")public String createOrder(@RequestParam String userId) {// 远程调用User.GetUserInfoResponse userInfo = userClient.getUserInfo(userId);// 处理订单逻辑return "为用户创建的订单:" + userInfo.getName()+userInfo.getAddress()+userInfo.getEmail();}
}

配置:application.yml

server:port: 10001grpc:client:grpc-user: # 自定义服务名address: 'static://127.0.0.1:9190' # 调用 gRPC 的地址negotiation-type: plaintext # 明文传输
spring:application:name: grpc-order

启动类

@SpringBootApplication
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class, args);}
}

7. 启动和运行微服务

确保用户服务和订单服务的端口配置正确,启动两个服务:

  • 启动用户服务,它会在指定的 gRPC 端口监听(如 9190)。
  • 启动订单服务,通过 gRPC 客户端调用用户服务来获取用户信息并处理订单。
    客户端调用地址
    http://localhost:10001/order?userId=123
    在这里插入图片描述
    服务端执行信息
    在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【网络安全】分享4个高危业务逻辑漏洞
  • 影刀RPE学习——自动化
  • 浅谈C#之AutoResetEvent和ManualResetEvent
  • 第k个排列 - 华为OD统一考试(E卷)
  • Java学习路线
  • 51单片机 - DS18B20实验1-读取温度
  • 浏览器指纹修改指南2024 - CommandLine(一)
  • 速盾:h5小游戏需要开cdn吗?
  • # windows 运行框输入mrt提示错误:Windows 找不到文件‘mrt‘。请确定文件名是否正确后,再试一次
  • 腾讯百度阿里华为常见算法面试题TOP100(3):链表、栈、特殊技巧
  • 基于C++实现(MFC)职工工作量统计系统
  • Android OkHttp源码分析(一):为什么OkHttp的请求速度很快?为什么可以高扩展?为什么可以高并发
  • Python 集成快递物流 API 助力订单追踪:轻松实现物流可视化
  • 如何让Windows控制台窗口不接受鼠标点击(禁用鼠标输入)
  • 面试真题-TCP的三次握手
  • 【Leetcode】101. 对称二叉树
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • [译]CSS 居中(Center)方法大合集
  • CAP理论的例子讲解
  • Fundebug计费标准解释:事件数是如何定义的?
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • JavaScript 一些 DOM 的知识点
  • Redux 中间件分析
  • Zepto.js源码学习之二
  • 初识MongoDB分片
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 浮现式设计
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 前端工程化(Gulp、Webpack)-webpack
  • 区块链技术特点之去中心化特性
  • 使用Swoole加速Laravel(正式环境中)
  • 微服务入门【系列视频课程】
  • 一个完整Java Web项目背后的密码
  • 你对linux中grep命令知道多少?
  • 阿里云API、SDK和CLI应用实践方案
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • (+4)2.2UML建模图
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (09)Hive——CTE 公共表达式
  • (1)Jupyter Notebook 下载及安装
  • (1)svelte 教程:hello world
  • (13)DroneCAN 适配器节点(一)
  • (145)光线追踪距离场柔和阴影
  • (2024,RWKV-5/6,RNN,矩阵值注意力状态,数据依赖线性插值,LoRA,多语言分词器)Eagle 和 Finch
  • (C语言)共用体union的用法举例
  • (六)c52学习之旅-独立按键
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (详细文档!)javaswing图书管理系统+mysql数据库
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • .bat文件调用java类的main方法
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET/C# 的字符串暂存池
  • .NET成年了,然后呢?
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • .vimrc 配置项