gRPC入门

gRPC开发流程开始

gRPC的设计思路基于HTTP/2,所以API也是基于Stream设计的:通常一次RPC请求可以理解为Stream从创建到销毁的过程,框架内封装了Stream的整个生命周期。


(一)调用模式

  1. Unary:请求响应模式
  2. Client Streaming:Client发送多次,Server响应一次
  3. Server Streaming:Server发送多次,Client响应一次
  4. 双向Streaming:C/S都发送多次

(二)Unary模式

1.Server端API

  1. StreamObserver
  2. ServerCall
  3. ServerCall.Listener

流程:通过.proto文件定义好service后生成XXXGrpc.class文件,里面提供了XXXImplBase抽象类,我只需继承该抽象类然后实现方法即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class XXXServiceImple extends XXXGrpc.XXXImplBase{
@Override
public void test(TestReq req, StreamObserver observer) {
try {
//get resp with req
observer.onNext(TestResp.newBuilder.result(resp).build() );
//onCompleted()和onError()都是终止请求的回调,不能同时选择
observer.onCompleted();
} catch(Exception e) {
//异常处理:将服务端异常封装成gRPC异常提供给客户端
//【注意】:如果不是服务器异常,而是是gRPC本身的异常(比如序列化错误)则不能如此捕获!需要定义拦截器!!!!
//Status.INVALID_ARGUMENT 参数错误
responseObserver.onError(Status.INVALID_ARGUMENT
//.withDescription 异常描述
.withDescription(e.getMessage() )
//.withCause 异常原因
.withCause(e)
//.asRuntimeException 转化为运行时异常,等价于:
//new StatusRuntimeException(Status.XXX.withDescription(e.getMessage() )...)
.asRuntimeException() );
log.error(e);
}

}
}

2.Client端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Lazy
@Component
public class XXXClient {
//读取配置文件,创建客户端
private final GrpcClient<XXXServiceFutureClient> client = GrpcClient.create(
XXXRpcConfig.xxxService);

public TestResp test(long uid) {
//调用入参构造器
TestReq req = TestReq.newBuilder().setUid(uid).build();
//异步:反射调用test()方法,传入入参,获取ListenableFuture对象
ListenableFuture<TestResp> future = client.
method(XXXServiceFutureClient::test).
call(req).toFuture();
//设置超时时间
return getUnchecked(future, 30, TimeUnit.MILLISECONDS);
}
}

(三)ProtocolBuffersprotobuf

ProtocolBuffers是谷歌推出的二进制序列化协议,提供IDL文件来定义各种类型的数据。目前整体协议版本是proto3protobuf提供了从.proto文件编译生成各个语言文件的功能。

1. .proto文件详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//在其他.proto文件导入该.proto文件,可以使用该文件的message

syntax = "proto3";

//.proto文件内部package指定位置,决定了service的全限定名,不要更改
package com.kuaishou.infra.grpc.test;

//.proto文件中message类的生成路径,如果修改会造成源码不兼容编译阻塞,不要更改
option java_package = "com.kuaishou.demo";
//输出文件名
option java_outer_classname = "Demo";
//指定.proto文件中的message是否生成独立的java文件,推荐开启,不要更改
option java_multiple_files = true;

//枚举
enum StatusEnum {
SUCCESS = 0; // 请求成功
SERVERERROR = 1; // 服务器错误
PARAMERROR = 2; // 入口参数错误
}

message TestRequest {
int64 user_id = 1;
}

message TestResponse {
StatusEnum result_code = 2;
bool validated = false;
}

//以下均为Unary模式
service TestService {
rpc Test (TestRequest) returns (TestResponse);
rpc TestDeadline (TestRequest) returns (TestResponse);
rpc TestCost (TestRequest) returns (TestResponse);
rpc TestEmpty (TestRequest) returns (TestResponse);
}

service TestStreamService {
rpc Test (TestRequest) returns (stream TestResponse); //Server Stream模式
rpc TestFailed (TestRequest) returns (stream TestResponse); //Server Stream模式
rpc TestSlow (TestRequest) returns (stream TestResponse); //Server Stream模式
rpc TestUpStream(stream TestRequest) returns (TestResponse); //Client Stream模式
rpc TestUpStreamSlow(stream TestRequest) returns (TestResponse); //Client Stream模式
rpc TestDuplex(stream TestRequest) returns (stream TestResponse); //C/S Stream模式
}

Java数据类型与protobuf数据类型对应关系如下,记住一定要给定初始值

  • Java:long -> protobuf:int64
  • Java:boolean -> protobuf:boolbool的初始值要是正整数

2. 生成桩代码:protobuf-maven-plugin

  1. mvn clean:清空target目录
  2. mvn package:根据项目生成JAR包
  3. mvn install:将JAR包安装在本地的Maven仓库
-------------本文结束感谢您的阅读-------------

本文标题:gRPC入门

文章作者:DragonBaby308

发布时间:2020年04月20日 - 22:47

最后更新:2020年04月24日 - 22:25

原始链接:http://www.dragonbaby308.com/grpc/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

急事可以使用右下角的DaoVoice,我绑定了微信会立即回复,否则还是推荐Valine留言喔( ఠൠఠ )ノ
0%