java版gRPC实战之三:服务端流

  1. 用proto生成代码

  2. 服务发布和调用

  3. 服务端流

  4. 客户端流

  5. 双向流

  6. 客户端动态获取服务端地址

  7. 基于eureka的注册发现

关于gRPC定义的四种类型

本文是《java版gRPC实战》系列的第三篇,前文咱们实战体验了简单的RPC请求和响应,那种简单的请求响应方式其实只是gRPC定义的四种类型之一,这里给出《gRPC 官方文档中文版》对这四种gRPC类型的描述:

  1. 简单 RPC:客户端使用存根(stub)发送请求到服务器并等待响应返回,就像平常的函数调用一样;

  2. 服务器端流式 RPC:客户端发送请求到服务器,拿到一个流去读取返回的消息序列。 客户端读取返回的流,直到里面没有任何消息;(即本篇内容)

  3. 客户端流式 RPC:客户端写入一个消息序列并将其发送到服务器,同样也是使用流。一旦 客户端完成写入消息,它等待服务器完成读取返回它的响应;

  4. 双向流式 RPC:是双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器 可以以任意喜欢的顺序读写:比如, 服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替 的读取和写入消息,或者其他读写的组合。 每个流中的消息顺序被预留;

本篇概览

本篇是服务端流类型的gRPC服务实战,包括以下内容:

  1. 开发一个gRPC服务,类型是服务端流;

  2. 开发一个客户端,调用前面发布的gRPC服务;

  3. 验证;

  • 不多说了,开始上代码;

源码下载

  • 本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):

| 名称 | 链接 | 备注 |

| :-- | :-- | :-- |

| 项目主页 | https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 |

| git仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https协议 |

| git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |

  • 这个git项目中有多个文件夹,《java版gRPC实战》系列的源码在grpc-tutorials文件夹下,如下图红框所示:

在这里插入图片描述

  • grpc-tutorials文件夹下有多个目录,本篇文章对应的服务端代码在server-stream-server-side目录下,客户端代码在server-stream-client-side目录下,如下图:

在这里插入图片描述

开发一个gRPC服务,类型是服务端流

  • 首先要开发的是gRPC服务端,一共要做下图所示的七件事:

在这里插入图片描述

  • 打开grpc-lib模块,在src/main/proto目录下新增文件mall.proto,里面定一个了一个gRPC方法ListOrders及其入参和返回对象,内容如下,要注意的是返回值要用关键字stream修饰,表示该接口类型是服务端流:

syntax = “proto3”;

option java_multiple_files = true;

// 生成java代码的package

option java_package = “com.bolingcavalry.grpctutorials.lib”;

// 类名

option java_outer_classname = “MallProto”;

// gRPC服务,这是个在线商城的订单查询服务

service OrderQuery {

// 服务端流式:订单列表接口,入参是买家信息,返回订单列表(用stream修饰返回值)

rpc ListOrders (Buyer) returns (stream Order) {}

}

// 买家ID

message Buyer {

int32 buyerId = 1;

}

// 返回结果的数据结构

message Order {

// 订单ID

int32 orderId = 1;

// 商品ID

int32 productId = 2;

// 交易时间

int64 orderTime = 3;

// 买家备注

string buyerRemark = 4;

}

  • 双击下图红框位置的generateProto,即可根据proto生成java代码:

在这里插入图片描述

  • 新生成的java代码如下图红框:

在这里插入图片描述

  • 在父工程grpc-turtorials下面新建名为server-stream-server-side的模块,其build.gradle内容如下:

// 使用springboot插件

plugins {

id ‘org.springframework.boot’

}

dependencies {

implementation ‘org.projectlombok:lombok’

implementation ‘org.springframework.boot:spring-boot-starter’

// 作为gRPC服务提供方,需要用到此库

implementation ‘net.devh:grpc-server-spring-boot-starter’

// 依赖自动生成源码的工程

implementation project(‘:grpc-lib’)

}

  • 新建配置文件application.yml:

spring:

application:

name: server-stream-server-side

gRPC有关的配置,这里只需要配置服务端口号

grpc:

server:

port: 9899

  • 启动类:

package com.bolingcavalry.grpctutorials;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public class ServerStreamServerSideApplication {

public static void main(String[] args) {

SpringApplication.run(ServerStreamServerSideApplication.class, args);

}

}

  • 接下来是最关键的gRPC服务,代码如下,可见responseObserver.onNext方法被多次调用,用以向客户端持续输出数据,最后通过responseObserver.onCompleted结束输出:

package com.bolingcavalry.grpctutorials;

import com.bolingcavalry.grpctutorials.lib.Buyer;

import com.bolingcavalry.grpctutorials.lib.Order;

import com.bolingcavalry.grpctutorials.lib.OrderQueryGrpc;

import io.grpc.stub.StreamObserver;

import net.devh.boot.grpc.server.service.GrpcService;

import java.util.ArrayList;

import java.util.List;

@GrpcService

public class GrpcServerService extends OrderQueryGrpc.OrderQueryImplBase {

/**

  • mock一批数据

  • @return

*/

private static List mockOrders(){

List list = new ArrayList<>();

Order.Builder builder = Order.newBuilder();

for (int i = 0; i < 10; i++) {

list.add(builder

.setOrderId(i)

.setProductId(1000+i)

.setOrderTime(System.currentTimeMillis()/1000)

.setBuyerRemark((“remark-” + i))

.build());

}

return list;

}

@Override

public void listOrders(Buyer request, StreamObserver responseObserver) {

// 持续输出到client

for (Order order : mockOrders()) {

responseObserver.onNext(order);

}

// 结束输出

responseObserver.onCompleted();

}

}

  • 至此,服务端开发完成,咱们再开发一个springboot应用作为客户端,看看如何远程调用listOrders接口,得到responseObserver.onNext方法输出的数据;

开发一个客户端,调用前面发布的gRPC服务

  • 客户端模块的基本功能是提供一个web接口,其内部会调用服务端的listOrders接口,将得到的数据返回给前端,如下图:

在这里插入图片描述

  • 在父工程grpc-turtorials下面新建名为server-stream-client-side的模块,其build.gradle内容如下:

plugins {

id ‘org.springframework.boot’

}

dependencies {

implementation ‘org.projectlombok:lombok’

implementation ‘org.springframework.boot:spring-boot-starter’

implementation ‘org.springframework.boot:spring-boot-starter-web’

implementation ‘net.devh:grpc-client-spring-boot-starter’

implementation project(‘:grpc-lib’)

}

  • 应用配置信息application.yml内容如下,可见是端口和gRPC服务端地址的配置:

server:

port: 8081

spring:

application:

name: server-stream-client-side

grpc:

client:

gRPC配置的名字,GrpcClient注解会用到

server-stream-server-side:

gRPC服务端地址

address: ‘static://127.0.0.1:9899’

enableKeepAlive: true

keepAliveWithoutCalls: true

negotiationType: plaintext

  • 服务端的listOrders接口返回的Order对象里面有很多gRPC相关的内容,不适合作为web接口的返回值,因此定义一个DispOrder类作为web接口返回值:

最后

由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档

MySQL全家桶笔记

还有更多面试复习笔记分享如下

Java架构专题面试复习

注解会用到

server-stream-server-side:

gRPC服务端地址

address: ‘static://127.0.0.1:9899’

enableKeepAlive: true

keepAliveWithoutCalls: true

negotiationType: plaintext

  • 服务端的listOrders接口返回的Order对象里面有很多gRPC相关的内容,不适合作为web接口的返回值,因此定义一个DispOrder类作为web接口返回值:

最后

由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档

[外链图片转存中…(img-TA28TW2m-1714135323499)]

还有更多面试复习笔记分享如下

[外链图片转存中…(img-cD4Xh6Ni-1714135323500)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值