Spring + Grpc + NacOS 集成
 使用Grpc之前需要了解的
 Grpc
Grpc与其他普通Rpc相同,都是屏蔽掉远程调用之间的细节,使得远程调用与本地调用一般,HTTP/2 是Grpc的默认使用协议。
 HTTP/2与HTTP/1.x
HTTP/1.x是一个文本传输协议,可读性非常好。HTTP/2是一个二进制协议,所有的数据传输并不易读。

Wireshark可以帮我们解析
下面这个是OpenFeign,基于HTTP/1.1


具体HTTP/1.x和HTTP/2的优缺点可以移步至
 Protocol Buffers
ProtoBuf 是google团队开发的用于高效存储和读取结构化数据的工具,你可以理解为另一种格式的JSON,正是因为如此,Java中普通的JSON序列化和反序列化工具对其不起作用,需要使用到
| <dependency><groupId>com.google.protobuf</groupId>
 <artifactId>protobuf-java-util</artifactId>
 </dependency>
 
 | 
来针对JSON和ProtoBuf相互转换
 proto文件
类似的,你会看到和下面文件相似的
| syntax = "proto3";
 option java_multiple_files = true;
 option java_package = "cn.bwte.grpc";
 option java_outer_classname = "TestProto";
 
 
 service Test {
 
 rpc SayHello (HelloRequest) returns (HelloReply) {
 }
 
 }
 
 
 message HelloRequest {
 string name = 1;
 }
 
 
 message HelloReply {
 string message = 1;
 }
 
 | 
可以理解为,定义了proto的协议版本,需要生成的javaClass包名和类名,还有定义的方法调用以及实体。
那我们怎么才能让这玩意生成Java实体呢
|  <plugins><plugin>
 <groupId>org.xolstice.maven.plugins</groupId>
 <artifactId>protobuf-maven-plugin</artifactId>
 <version>${protobuf-plugin.version}</version>
 <configuration>
 <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
 <pluginId>grpc-java</pluginId>
 <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
 </configuration>
 <executions>
 <execution>
 <goals>
 <goal>compile</goal>
 <goal>compile-custom</goal>
 </goals>
 </execution>
 </executions>
 </plugin>
 </plugins>
 
 | 
Maven是个好东西,添加了这个之后,在每次的install都会根据proto生成你定义的实体
 理论存在 实践开始
 准备阶段
 技术选型
目前Spring官方也出了对于Grpc的调用组建,合并在全家桶中,但是对于Java和Spring的要求比较高,需要 Spring Boot 3.4.x and 3.5.x,感兴趣的同学可以Getting Started
本文采用的是grpc-spring,一个第三方Grpc的实现
 Grpc接口定义
| <properties><protobuf.version>3.23.4</protobuf.version>
 <protobuf-plugin.version>0.6.1</protobuf-plugin.version>
 <grpc.version>1.58.0</grpc.version>
 </properties>
 <dependencies>
 <dependency>
 <groupId>io.grpc</groupId>
 <artifactId>grpc-stub</artifactId>
 <version>${grpc.version}</version>
 </dependency>
 <dependency>
 <groupId>io.grpc</groupId>
 <artifactId>grpc-protobuf</artifactId>
 <version>${grpc.version}</version>
 </dependency>
 </dependencies>
 插件引入上文说的那个Maven插件,需要用来生成
 
 | 
 定义proto
| syntax = "proto3";
 option java_multiple_files = true;
 option java_package = "cn.ashes.grpc";
 option java_outer_classname = "CustomerProto";
 
 service Customer {
 rpc queryCustomerInfo (CustomerRequest) returns (CustomerReplyList) {
 }
 }
 message CustomerReplyList {
 repeated CustomerReply replies = 1;
 }
 
 message CustomerReply {
 int64 id = 1;
 string customerCode = 2;
 string customerName = 3;
 
 }
 
 
 message CustomerRequest {
 string customerName = 1;
 int32 pageNo = 2;
 int32 pageSize = 3;
 }
 
 
 | 
在进行install之后,就会生成对应的GrpcService与实体
 服务端实现
 实现Service
| @GrpcService
 public class CustomerService extends CustomerGrpc.CustomerImplBase {
 
 @Resource
 private CustomerController customerController;
 
 @Override
 public void queryCustomerInfo(CustomerRequest request, StreamObserver<CustomerReplyList> responseObserver) {
 String json;
 try {
 
 json = JsonFormat.printer().print(request);
 } catch (InvalidProtocolBufferException e) {
 throw new RuntimeException(e);
 }
 CustomerInfoQuery bean = JSONUtil.toBean(json, CustomerInfoQuery.class);
 CustomerInfo customerInfoJsonResult = customerController.queryCustomerInfo(bean);
 CustomerReplyList.Builder listBuilder = CustomerReplyList.newBuilder();
 
 customerInfoJsonResult.getData().forEach(customerInfo -> {
 String json1 = JSONUtil.toJsonStr(customerInfo);
 
 CustomerReply.Builder builder = CustomerReply.newBuilder();
 
 
 try {
 JsonFormat.parser().ignoringUnknownFields().merge(json1, builder);
 listBuilder.addReplies(builder.build());
 } catch (InvalidProtocolBufferException e) {
 throw new RuntimeException(e);
 }
 });
 responseObserver.onNext(listBuilder.build());
 responseObserver.onCompleted();
 }
 }
 
 | 
服务端事例为调用查询客户信息
简单的测试下叭
| grpcurl --plaintext localhost:9099 list Customer
 grpcurl --plaintext -d '{"customerName": "喵喵"}' localhost:9099 Customer.queryCustomerInfo
 
 | 
你说你没有grpcurl?指路grpcurl
你要是有HomeBrew就更爽了直接brew install grpcurl
理想情况你就会得到正确的反差了
 客户端实现
但是我想用其他微服务来调用怎么办捏
注册服务到注册中心会把?那我不教了
下一步就是写客户端
 依赖注入
| @GrpcClient("Grpc的Service在注册中心的名字")private CustomerGrpc.CustomerBlockingStub customerBlockingStub;
 
 | 
这里我们用Block的实现来做事例,Grpc给我们三种实现NewBlockingStub 、 newStub 、 newFutureStub
分别代表阻塞调用,纯异步调用客户端,异步带Future调用
| CustomerRequest build = CustomerRequest.newBuilder().setCustomerName("喵喵")
 .setPageNo(1)
 .setPageSize(100).build();
 CustomerReplyList customerReplyList = customerBlockingStub.queryCustomerInfo(build);
 
 | 
直接调用就可以了
 延展阅读
- Grpc
- HTTP/2对比HTTP/1.1,特性是什么?是如何解决队头阻塞与压缩头部的?
- 详解HTTP协议版本(HTTP/1.0、1.1、2.0、3.0区别)
- Protocol Buffer 基础知识:Java
- grpc-spring
- Getting Started
- grpcurl
- gRPC三种客户端类型实践【Java版】