说明文档:http://doc.oschina.net/grpc?t=60134

参考文档:https://zhuanlan.zhihu.com/p/377860784

参考文档:https://baijiahao.baidu.com/s?id=1762269686952396195&wfr=spider&for=pc

依赖

1
2
3
4
5
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>
</dependency>
1
2
3
4
5
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>
</dependency>

如果服务只作为grpc服务端或者grpc客户端,建议只引入对应的依赖,不要引入grpc-spring-boot-starter

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
<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.5.1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier}</pluginArtifact>
<!--设置proto文件目录-->
<protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
<!--设置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>
</plugins>
</build>

os-maven-plugin和protobuf-maven-plugin都需要

配置

1
2
3
4
5
server.port=8080
spring.application.name=grpc-server
#如果使用nacos,则加入此配置
#spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
grpc.server.port=9090
1
2
3
4
5
6
7
8
9
10
11
#如果使用nacos或者其他中间件作为注册与发现中心,则不需要此配置
grpc.client.grpc-server.address=static://localhost:9090
grpc.client.grpc-server.enableKeepAlive=true
grpc.client.grpc-server.keepAliveWithoutCalls=true
grpc.client.grpc-server.negotiationType=plaintext

spring.application.name=grpc-client
#如果使用nacos,则加入此配置
#spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

server.port=8081

编写proto文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.example.client.proto";//生成代码的位置

service EventInfoService {
rpc sendMessageEvent(EventInfoMessage) returns (EventInfoResponse) {}
}

message EventInfoMessage {
string msg = 1;
}


message EventInfoResponse {
int32 code = 1;
string msg = 2;
bool success = 3;
}

proto文件编写还比较简单

  1. service EventInfoService:代表要创建一个名为EventInfoService的类,并且具有sendMessageEvent方法,这个方法需要指定入参和反参,指定的入参和反参都要此文件中或者引入的其他proto文件中定义,这个方法代表了访问服务端的接口,所以proto文件服务端与客户端要一致,生成的代码中会有三个不同的io.grpc.stub.AbstractStub实现类和一个io.grpc.BindableService的实现类,前者是为客户端实现的,客户端调用请求方法在前者中实现的,后者是为了服务端实现的,实现了服务端接收请求的方法,四个实现类都会实现自定义的请求方法
    1. XXXServiceBlockingStub:代表阻塞的实现我们定义的方法(例如上面的sendMessageEvent),即发送消息的方法会阻塞直到客户端接收到服务端的响应,即上面的EventInfoResponse
    2. XXXServiceFutureStub:代表等待的实现我们定义的方法,即发送消息后会立即返回一个com.google.common.util.concurrent.ListenableFuture<自定义返回参数>,但是调用ListenableFuture的get方法时会阻塞
    3. XXXServiceStub:代表完全异步的实现我们定义的方法,即发送消息时,需要我们传入一个回调方法并且不会返回参数,回调方法实现io.grpc.stub.StreamObserver<自定义返回参数>即可
    4. XXXServiceImplBase:实现了处理请求的方法
  2. message EventInfoMessage:代表创建一个名为EventInfoMessage的消息类
  3. message EventInfoResponse:代表创建一个名为EventInfoResponse的消息类

通过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
@RestController
public class ClientController {

@GrpcClient("grpc-server")
private EventInfoServiceGrpc.EventInfoServiceBlockingStub eventInfoServiceBlockingStub;

@GrpcClient("grpc-server")
private EventInfoServiceGrpc.EventInfoServiceFutureStub eventInfoServiceFutureStub;

@GrpcClient("grpc-server")
private EventInfoServiceGrpc.EventInfoServiceStub eventInfoServiceStub;

@RequestMapping(value = "/query/{str}")
public String queryUser(@PathVariable String str) throws ExecutionException, InterruptedException {
EventInfoResponse eventInfoResponse = eventInfoServiceBlockingStub.sendMessageEvent(EventInfoMessage.newBuilder().setMsg("success").build());
System.out.println(eventInfoResponse.getMsg());
ListenableFuture<EventInfoResponse> eventInfoResponseListenableFuture = eventInfoServiceFutureStub.sendMessageEvent(EventInfoMessage.newBuilder().setMsg("success").build());
System.out.println(eventInfoResponseListenableFuture.get().getMsg());
eventInfoServiceStub.sendMessageEvent(EventInfoMessage.newBuilder().setMsg("success").build(), new StreamObserver<EventInfoResponse>() {
@Override
public void onNext(EventInfoResponse response) {
System.out.println(response.getMsg());
}

@Override
public void onError(Throwable throwable) {
new Exception(throwable).printStackTrace();
}

@Override
public void onCompleted() {
System.out.println("complete");
}
});
return "success";
}
}

这里展示三个AbstractStub实现类的用法示例,客户端会使到io.grpc.ClientCall类

服务端响应代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@GrpcService
public class EventInfoServiceGrpcImpl extends EventInfoServiceGrpc.EventInfoServiceImplBase {

@Override
public void sendMessageEvent(EventInfoMessage request, StreamObserver<EventInfoResponse> responseObserver) {
EventInfoResponse.Builder eventInfo = EventInfoResponse.newBuilder();
//业务处理
String msg = request.getMsg();
//
if ("success".equals(msg)){
eventInfo.setCode(200).setMsg("success"+100000).setSuccess(true);
}else{
eventInfo.setCode(500).setMsg("error"+100000).setSuccess(false);
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
responseObserver.onNext(eventInfo.build());
responseObserver.onCompleted();
}

}

服务端请求响应处理类需要继承BindableService的实现类并实现我们自定义方法名称的方法,服务端使用了ServerCall


本站总访问量:次本站总访问数:人
本站由 Peng Tong 使用 Stellar 1.29.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。