写点什么

gRPC 快速整合 SpringCloud

作者:Java你猿哥
  • 2023-03-22
    湖南
  • 本文字数:4199 字

    阅读完需:约 14 分钟

gRPC快速整合SpringCloud

gRPC 是由 google 开发的一个高性能、通用的开源 RPC 框架,主要面向移动应用开发且基于 HTTP/2 协议标准而设计,同时支持大多数流行的编程语言。它是一种与语言、平台无关、可扩展的序列化结构数据。它的定位类似于 JSON、XML,但是比他们更小、更快、更简单。

优势

gRPC 基于 HTTP/2 协议传输,而 HTTP/2 相比 HTTP1.x,还是有需要优势的:

  • HTTP/2 采用二进制格式传输协议,而非 HTTP1.x 的文本格式。

  • 多路复用

HTTP/2 支持通过一个连接发送多个并发的请求。

  • 服务器推送

服务端推送是一种在客户端请求之前发送数据的机制。在 HTTP/2 中,服务器可以对客户端的一个请求发送多个响应。而不像 HTTP/1.X 一样,只能通过客户端发起 request,服务端才产生对应的 response。

  • 减少网络流量的头部压缩

HTTP/2 对消息头进行了压缩传输,能够节省消息头占用的网络流量。

工作方式


从上图可以看出,简单了解一下 grpc 的工作模式。用 gRPC 来进行远程调用服务,客户端(client) 仅仅需要 gRPC Stub ,通过 Proto Request 向 gRPC Server 发起服务调用,然后 gRPC Server 通过 Proto Response(s)将调用结果返回给调用的 client。

使用场景

  • 接口约束: 需要对接口有严格的管控,比如对外部提供接口时,并不希望客户端随意传递数据,这是我们就可以使用 gRPC 来对接口约束。

  • 性能要求:对传输性能有较高要求,如果我们传输的消息体过大,或调度过于频繁不希望影响系统性能时,可以考虑使用 gRPC,它的消息体比 JSON 或者文本传输要小的多。

Protobuf 语法

基本规范

  • 文件以.proto 做为文件后缀,除结构定义外的语句以分号结尾

  • 结构定义可以包含:message、service、enum

  • rpc 方法定义结尾的分号可有可无

  • Message 命名采用驼峰命名方式,字段命名采用小写字母加下划线分隔方式

  • Enums 类型名采用驼峰命名方式,字段命名采用大写字母加下划线分隔方式

  • Service 与 rpc 方法名统一采用驼峰式命名

message SongServerRequest {    required string song_name = 1;   } 
enum Foo { FIRST_VALUE = 1; SECOND_VALUE = 2; }
复制代码


限定修饰符

  • Required: 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置 required 字段或者无法识别 required 字段都会引发编解码异常,导致消息被丢弃。

  • Optional:表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。

  • Repeated:表示该字段可以包含 0~N 个元素。其特性和 optional 一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。

数据类型

gRPC 整合 SpringCloud & Nacos

其实,第一次了解 gRPC,也是在 Nacos2.0 升级的时候,Nacos2.0 版本相比 1.X 新增了 gRPC 的通信方式。


核心依赖

 <properties>        <java.version>8</java.version>        <nacos.version>2.2.5.RELEASE</nacos.version>        <mapstruct.version>1.3.1.Final</mapstruct.version>        <grpc.starter.version>2.10.1.RELEASE</grpc.starter.version>        <grpc.client.version>2.10.1.RELEASE</grpc.client.version>        <lombok.version>1.18.12</lombok.version>        <fastjson.version>1.2.76</fastjson.version>        <freemarker.verson>2.3.28</freemarker.verson>        <nacos.client>2.0.0</nacos.client>    </properties>    <dependency>       <groupId>net.devh</groupId>       <artifactId>grpc-client-spring-boot-starter</artifactId>       <version>${grpc.client.version}</version>    </dependency>    <dependency>        <groupId>net.devh</groupId>        <artifactId>grpc-server-spring-boot-starter</artifactId>        <version>${grpc.starter.version}</version>    </dependency>
复制代码

项目结构


API

  • 编写 pom 配置。

<dependencies>        <dependency>            <groupId>net.devh</groupId>            <artifactId>grpc-server-spring-boot-starter</artifactId>        </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> <!--设置grpc生成代码到指定路径--> <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>
<!-- 设置多个源文件夹 --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>3.0.0</version> <executions> <!-- 添加主源码目录 --> <execution> <id>add-source</id> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>${project.basedir}/src/main/gen</source> <source>${project.basedir}/src/main/java</source> </sources> </configuration> </execution> </executions> </plugin>
</plugins> </build>
复制代码


  • 新建 src\main\proto 目录,编写 user.ptoto。

syntax = "proto3";
option java_multiple_files = true;option java_package = "com.yx.grpc.user";
service UserService { rpc queryUser(UserRequest) returns (UserReply) {}}message UserRequest { int64 id = 2;}message UserReply { int32 code = 1; string msg = 2; bool success = 3; message Data { UserPb userPb = 1; } Data data = 4;}
message UserPb { int64 id = 1; string name = 2; string sex = 3;}
复制代码
  • 执行 mvn compile,生成代码。


服务端

  • 核心服务实现类。

@GrpcServicepublic class UserServiceImpl  extends UserServiceGrpc.UserServiceImplBase{
@Override public void queryUser(UserRequest request, StreamObserver<UserReply> responseObserver) { UserReply.Builder userReply = UserReply.newBuilder(); TblUser tblUser = new TblUser(11L, "syx", "nan"); userReply.setCode(200).setMsg("SUCCESS").setSuccess(true); userReply.setData(UserReply.Data.newBuilder() .setUserPb(UserPb.newBuilder() .setId(tblUser.getId()) .setName(tblUser.getName()) .setSex(tblUser.getSex()))); responseObserver.onNext(userReply.build()); responseObserver.onCompleted(); super.queryUser(request, responseObserver); }}
复制代码


客户端

  • gRPC 配置。

grpc:  client:    GLOBAL:      negotiation-type: plaintext      enable-keep-alive: true      keep-alive-without-calls: true
复制代码


  • 自定义请求转换器。

@Configurationpublic class MessageConverter {
@Bean public HttpMessageConverters protobufHttpMessageConverter() { ProtobufHttpMessageConverter protobufHttpMessageConverter = new ProtobufHttpMessageConverter(); protobufHttpMessageConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.APPLICATION_JSON, MediaType.parseMediaType(MediaType.TEXT_PLAIN_VALUE + ";charset=ISO-8859-1"))); return new HttpMessageConverters(protobufHttpMessageConverter); }
}
复制代码


  • 请求测试类。

@RestController@RequestMapping("/user")@Slf4jpublic class UserController {
@GrpcClient("yx-grpc-service") UserServiceGrpc.UserServiceFutureStub futureStub;
@RequestMapping(value="/queryUser/{id}") public UserReply queryUser(@PathVariable Integer id) { UserReply userReply = null; try { userReply = futureStub.queryUser(UserRequest.newBuilder().setId(id).build()).get(); return userReply; } catch (Exception e) {
} return userReply; }}
复制代码

测试

启动服务端和客户端,访问 http://localhost:8002/user/queryUser/1 。



Gitee 地址:gitee.com/renxiaoshi/…

最后

不要白嫖!请点赞、关注给小编动力,谢谢观看!

用户头像

Java你猿哥

关注

一只在编程路上渐行渐远的程序猿 2023-03-09 加入

关注我,了解更多Java、架构、Spring等知识

评论

发布
暂无评论
gRPC快速整合SpringCloud_Java_Java你猿哥_InfoQ写作社区