十六.SpringCloudAlibaba极简入门-整合Grpc代替OpenFeign

前言

他来了他来了,停了快2个月了终于又开始更新文章啦,这次带来的绝对是干货!!!。由于公司项目进行重构的时候考虑到,OpenFeign做为服务通信组件在高并发情况下有一定的性能瓶颈,所以将其替换为更高性能的通信组件Grpc,Grpc也是业界比较流行的服务通信组件,底层采用HTTP/2进行网络通信性能上高于基于Http/1.1的OpenFeign。 我将把Grpc的整合过程整理成文字分享给大家,喜欢请三连!!!,你的鼓励是我坚持下去的动力。

认识Grpc

OpenFeign基于 HTTP/1.1 协议。主要使用 JSON 或 XML 格式进行数据交换,这些格式更加人性化但分装臃肿效率较低。其主要用于 RESTful API 调用,支持声明式的 Web 服务客户端。

而 gRPC 是一个高性能、开源和通用的 RPC(远程过程调用)框架,基于 Protocol Buffers 序列化协议开发,在内部实现上,它采用了 HTTP/2 协议作为传输层协议的一部分来实现高效的双向流通信的能力等特性让它成为很多开发者热衷的工具库之一;gRPC 在处理大量数据时表现优异,适用于需要快速响应的应用场景,特别是在微服务架构中。

gRPC:

  • 强调高效的数据传输和低延迟通信。如金融交易、在线游戏等对延迟要求极高的场景
  • 适合构建高性能的分布式系统和服务间通信。在大规模微服务架构中,gRPC 可以显著提高系统的整体性能。
  • 支持流式传输,可以实现长连接和实时数据推送。

OpenFeign:

  • 注重简化开发者的代码编写工作。
  • 更加灵活,可以轻松地集成到现有的 Spring Boot 项目中。
  • 适用于轻量级的 RESTful API 调用。

总结来说,gRPC 和 OpenFeign 各有优势,选择哪种技术取决于具体的业务需求和技术栈。如果你需要高性能、低延迟的服务间通信,gRPC 是更好的选择;如果你希望简化开发流程并快速集成 RESTful API,OpenFeign 则更为合适。

案例实战

1.搭建工程

首先搭建一个SpringBoot父工程,父工程下分别有:grpc-api ,grpc-provider ,grpc-consumer 三个模块,分别代表:Grpc接口,生产者,消费者。父工程管理的依赖如下

<properties><maven.compiler.source>21</maven.compiler.source><maven.compiler.target>21</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>21</java.version><skipTests>true</skipTests><spring-cloud.version>2023.0.1</spring-cloud.version><spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version><hutool.version>5.8.28</hutool.version><lombok.version>1.18.32</lombok.version></properties><!--SpringBoot依赖--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.0</version></parent><dependencies><!--   常用工具类     --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><scope>provided</scope></dependency><!--SpringCloud 2020.* 禁用了bootstrap 而注册中心等配置文件需要 bootstrap.yml 为名的配置文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><!--注解配置器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

2.API模块

api模块需要导入grpc相关依赖,以及编写proto文件,我们根据proto文件自动生成Grpc的API接口文件,需要导入的依赖如下

<dependencies><!-- https://mvnrepository.com/artifact/net.devh/grpc-server-spring-boot-starter --><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>3.0.0.RELEASE</version></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>3.0.0.RELEASE</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.2</version></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.12.0:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier}</pluginArtifact><outputDirectory>${project.basedir}/src/main/java</outputDirectory><clearOutputDirectory>false</clearOutputDirectory></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build>

grpc-server-spring-boot-starter 和 grpc-client-spring-boot-starter 是Grpc的服务端和客户端的依赖,javax.annotation-api是对Grpc代码生成注解的支持,不导入该包会报错。然后导入了os-maven-plugin插件,以及 protobuf-maven-plugin 插件用来根据proto文件生成API代码的。

接着我们再API模块中main目录下创建一个proto目录,并创建一个文件User.proto,内容如下

syntax = "proto3";
/** 生产的代码合并到一个文件 **/
option java_multiple_files = false;
/** 生产代码输出的包路径 **/
option java_package = "cn.whale.api.User";/** API接口 **/
service UserApi {/** Grpc API 接口 **/rpc getById(GetUserReq) returns (GetUserRep) {}
}/** 响应对象 **/
message GetUserReq {/** Long 用户ID **/int64 id = 1;
}/** 结果对象 **/
message GetUserRep {/** Long 用户ID **/int64 id = 1;/** String 用户名字 **/string name = 2;
}

该文件是用来定义Grpc Api接口的,具体请看上面的注释,需要注意的是定义Protobuf 的 message 对象的字段类型可不能使用Java的类型,int64 对应Long, string 对应 String 具体请看:https://protobuf.com.cn/programming-guides/proto3/#specifying-types

编写好proto文件后,对api模块进行compile(IDEA 右侧 - api模块 - lifecycle - compile) ,然后会自动在API模块中生成Grpc相关的 API接口。
在这里插入图片描述

3.提供者服务

提供者服务首先是需要向Nacos注册(其他注册中心也行)的,然后导入api模块,编写Grpc的提供者服务,导入如下依赖

    <dependencies><!--grpc api 模块 --><dependency><groupId>cn.whale</groupId><artifactId>grpc-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--nacos服务发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--配置管理 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--grpc服务端依赖,api模块中引入了,这里其实可以不引--><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>3.0.0.RELEASE</version></dependency></dependencies>

接着对提供者服务进行配置,启动类正常写,没有什么新东西,bootstrap.yml配置如下

server:port: 8081 #tomcat 端口
grpc:server:port: 7071 #Grpc端口client: #Grpic客户端配置GLOBAL:negotiation-type: plaintext #协议类型,明文传输,也可以使用TLS进行加密传输,服务内部通信使用明文即可enable-keep-alive: truekeep-alive-without-calls: true
spring:application:name: grpc-provider #服务名cloud:nacos:discovery: #服务注册server-addr: nacos地址:8848config: #配置管理server-addr: ${spring.cloud.nacos.discovery.server-addr}file-extension: yml

接下来编写提供者服务的Grpc实现,创建一个类UserApiImpl 继承UserApiGrpc,具体如下

package cn.whale.grpc;import cn.whale.api.User.User;
import cn.whale.api.User.UserApiGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;/*** 标记Grpc提供者服务*/
@GrpcService
public class UserApiImpl extends UserApiGrpc.UserApiImplBase {/*** 接口方法实现* @param request :请求对象* @param responseObserver : 消息流对象,用来响应结果*/@Overridepublic void getById(User.GetUserReq request, StreamObserver<User.GetUserRep> responseObserver) {long id = request.getId();//TODO :去数据查询数据//封装结果数据User.GetUserRep userRep = User.GetUserRep.newBuilder().setId(id).setName("zs").build();//响应结果responseObserver.onNext(userRep);responseObserver.onCompleted();//异常情况//responseObserver.onError(exception);}
}
  • @GrpcService :Grpc的服务端注解
  • UserApiGrpc.UserApiImplBase :根据Proto自动生成的API接口
  • getById :我们定义的API接口方法,具体请看代码注释

到这里提供者就编写完成了,启动提供者服务,可以看到Grpc的端口

在这里插入图片描述

4.消费者服务

消费者服务也是要做服务注册,然后引入api模块,以及Grpc客户端依赖,具体如下

<dependencies><dependency><groupId>cn.whale</groupId><artifactId>grpc-api</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>3.0.0.RELEASE</version></dependency></dependencies>

编写启动类和创建bootstrap.yml文件

server:port: 8082
grpc:server:port: 7072client:GLOBAL:negotiation-type: plaintextenable-keep-alive: truekeep-alive-without-calls: true
spring:application:name: grpc-consumercloud:nacos:discovery:server-addr: nacos地址:8848config:server-addr: ${spring.cloud.nacos.discovery.server-addr}file-extension: yml

接着我们编写一个Conroller来实现和提供者的Grpc通信,代码如下

@RestController
@Slf4j
public class BusinessController {//指向提供者的服务名@GrpcClient(value = "grpc-provider")private UserApiGrpc.UserApiBlockingStub userApiBlockingStub;@GetMapping("/user")public String getUserById(){User.GetUserRep getUserRep = userApiBlockingStub.getById(User.GetUserReq.newBuilder().setId(1L).build());log.info("查询到用户信息,id =  {},name = {}",getUserRep.getId(),getUserRep.getName());return getUserRep.toString();}
}
  • @GrpcClient(value = “grpc-provider”) : 客户端注解,value指向了注册中心的提供者服务的名字,底层会自动进行负载均衡
  • UserApiGrpc.UserApiBlockingStub : Grpc 同步接口,它也支持异步调用UserApiGrpc.UserApiFutureStub

到这里消费者就编写完成了,启动消费者,通过浏览器访问/user,就可以拿到提供者返回的数据了

在这里插入图片描述

5.注意事项

最后说几个注意事项

  1. Grpc生成的对象只提供了Builder的方式设置值,所以没办法通过BeanUtils等工具进行对象之间的自动转换的,需要手动给Proto对象设置值。见生产者 User.GetUserRep
  2. 如果给Proto对象设置了空值会报错,所以在给对象设置值的时候建议先判断空值,然后给一个默认值,比如:String为null,就指定一个“”空字符串
  3. Grpc是无法返回一个null对象的,所以消费者端到底有没有拿到一个有效的结果不能直接用null来判断,需要取出具体的值来判断

就写到这把,剩下的坑大家自己去踩,如果文章对你有帮助请给个好评!!!

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

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

相关文章

【Linux】环境变量详解

Linux环境变量 1.环境变量分类2.环境变量相关指令3.常用的环境变量4.环境变量的组织方式5.获取环境变量6.命令行参数 1.环境变量分类 按生命周期划分&#xff1a; 永久的&#xff1a;在环境变量脚本文件中配置&#xff0c;用户每次登录时会自动执行这些脚本&#xff0c;相当于永…

SpringBoot项目搭建IEDA2023.1.2

导入依赖 ——————————————————

L0G1000 Linux基础知识(包含ssh报错处理)

1.vscode通过ssh链接云服务器 按教程https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/linux 出现报错&#xff0c;是ssh配置原因 [23:40:18.788] Log Level: 2 [23:40:18.807] SSH Resolver called for “ssh-remotessh.intern-ai.org.cn”, attempt 1 [23:40:18.8…

使用 PyTorch-BigGraph 构建和部署大规模图嵌入的完整教程

当涉及到图数据时&#xff0c;复杂性是不可避免的。无论是社交网络中的庞大互联关系、像 Freebase 这样的知识图谱&#xff0c;还是推荐引擎中海量的数据量&#xff0c;处理如此规模的图数据都充满挑战。 尤其是当目标是生成能够准确捕捉这些关系本质的嵌入表示时&#xff0c;…

测试标题1111

前言 本文是该专栏的第68篇&#xff0c;后面会持续分享python爬虫干货知识&#xff0c;记得关注。 在本专栏之前&#xff0c;笔者有详细介绍京东滑块验证码的解决方法&#xff0c;感兴趣的同学&#xff0c;可以直接翻阅文章《Python如何解决“京东滑块验证码”(5)》进行查看。…

JDK8-17新特性

1.Java8新特性-Lambda表达式 2.1关于Java8新特性简介 Java 8是Java编程语言的一个重大版本更新&#xff0c;于2014年3月发布。它引入了许多新特性和改进&#xff0c;使得Java编程更加方便和高效。 下面是Java 8的主要新特性&#xff1a; Lambda表达式&#xff1a;Lambda表达式…

如何确保Python爬虫程序的稳定性和安全性?

在当今数字化时代&#xff0c;Python爬虫被广泛应用于数据采集和信息抓取。然而&#xff0c;确保爬虫程序的稳定性和安全性是开发过程中的重要考虑因素。本文将探讨如何通过技术手段和最佳实践来提高Python爬虫的稳定性和安全性&#xff0c;并提供代码示例。 稳定性保障 1. 异…

Axure二级菜单下拉交互实例

1.使用boxlabe进行基础布局 2.设置鼠标悬浮和选中状态 3.转换为动态面板 选中所有二级菜单,进行按钮组转换 选中所有二级菜单,进行动态面板转换 4.给用户管理增加显示/隐藏事件 1)选择toggle代表上拉和下拉切换加载 2)勾选Bring to Front,并选择Push/Pull Widgets代表收缩时…

基于智能推荐的图书电商系统的设计与实现

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

JavaScript实现Promise

第一步&#xff1a;编写constructor构造方法 const PENDING pending; const FULFILLED fulfilled; const REJECTED rejected;class MyPromise {#state PENDING;#result undefined;constructor(executor) {const resolve (data) > {this.#changeState(FULFILLED, data…

物理 + 人工智能 = 2024年诺贝尔物理学奖

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《热点时事》 期待您的关注 目录 引言 一、机器学习与神经网络的发展前景 二、机器学习和神经网络的研究与传统物理学的关系 结…

C++:异常

1. 异常的概念 C语言主要通过错误码的方式处理错误&#xff0c;错误码本质上就是对错误信息进行分类编号&#xff0c;拿到错误码以后还要去查询错误信息&#xff0c;比较麻烦。异常时抛出一个对象&#xff0c;这个对象可以涵盖更全面的信息。 异常处理机制允许程序中独立开发的…

南京邮电大学算法设计-二叉树先序遍历算法动态演示

二叉树先序遍历算法动态演示 一、课题内容和要求 (1)实验目的&#xff1a; 本实验通过手动输入二叉树结点信息&#xff0c;构建相应的二叉树&#xff0c;并通过图形化界面动态演示先序遍历算法的过程。通过本次实验&#xff0c;我可以深入理解二叉树的数据结构、先序遍历算法…

【开源免费】基于Vue和SpringBoot的在线考试系统(附论文)

本文项目编号 T 624 &#xff0c;文末自助获取源码 \color{red}{T624&#xff0c;文末自助获取源码} T624&#xff0c;文末自助获取源码 网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现…

高阶C语言之六:程序环境和预处理

本文介绍程序的环境&#xff0c;在Linux下对编译链接理解&#xff0c;较为简短&#xff0c;着重在于编译的步骤。 C的环境 在ANSI C&#xff08;标准C语言&#xff09;的任何一种实现中&#xff0c;存在两个不同的环境。 翻译环境&#xff1a;在这个环境中&#xff0c;源代码…

HarmonyOs鸿蒙开发实战(10)=>状态管理-对象数组的属性数据变更刷新UI,基于@Observed 和@ObjectLink装饰器

1.条件:基于HarmonyOs5.0.0版本. 2.功能要求&#xff1a;横向列表中每个景点的名称&#xff08;eg: 第二项 “灵隐寺” &#xff09;, 在通过天气接口拿到对应天气后&#xff0c;拼接到名称后面 > 变成&#xff08;“灵隐寺” 天气&#xff09;&#xff09; 3.老规矩先看…

快速上手Mybatis Plus并速通MybatisPlus所有知识点

目录 一、简介 1.1 概况 1.2 特性 二、快速入门 1.建表 2.引依赖 3.application.ymal文件 4.定义mapper继承BaseMapper 5.总结 三、Mybatis Plus的使用 1.常见注解 1.1 TableName 1.2 TableId 1.3 TableField 2.常见配置 3.BaseMapper的基础CRUD方法 4.Wrapper…

使用代理解决前端跨域问题详解

目录 前言1. 什么是跨域问题&#xff1f;1.1 同源策略的定义1.2 跨域问题的表现 2. 解决跨域问题的常见方法3. 在 Vite 中配置代理解决跨域问题3.1 环境准备3.2 配置代理3.2.1 配置基础路径3.2.2 配置 Vite 代理3.2.3 参数解释 3.3 验证代理功能 4. 深入分析与注意事项4.1 代理…

使用MaxKB搭建知识库问答系统并接入个人网站(halo)

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;使用MaxKB搭建知识库问答系统并接入个人网站 前言 从OpenAI推出ChatGPT到现在&#xff0c;大模型已经渗透到各行各业&#xff0c;大模型也逐渐趋于平民化&#xff1b;从最开始对其理解、生成、强大的知识积累的惊叹&…

查看台式机主机支持的最大分辨率 | 显卡和显示器

通过检查显卡规格和型号&#xff0c;确认主机支持最大分辨率。 方法1&#xff1a;设置 在设置 -> 系统 -> 屏幕 及其内的高级显示设置 设置 -> 显示 方法2&#xff1a;cmd 在运行中输入“devmgmt.msc”&#xff0c;进入设备管理器界面&#xff0c;点击展开“显示适配…