RPC框架——gRPC简单示例
1. 简介
- Google gRPC 是一款RPC框架
- 官方网址: gRPC
- 主要支持: C/C++, C#, Dart, GO, Java, Objective-C, Python, PHP, Ruby, Node.js
- gRPC主要由2部分构成
- 远程过程调用
- 数据序列化/反序列化 (Protocol Buffers)
2. 将*.proto 协议文件转换为语言源文件
- 安装Maven插件(用于编译*.proto 文件)
<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.10.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.25.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
- 编写 my_protocol.proto文件 (官方IDL说明)
syntax = "proto3"; // 包名 package com.skey.grpcdemo.grpc; option java_package = "com.skey.grpcdemo.grpc"; //option java_outer_classname = "PersonProto"; option java_multiple_files = true; // 定义一个JavaBean message Person { int32 id = 1; string name = 2; int32 age = 3; } // 定义一个请求 message MyRequest { int32 id = 1; } // 定义一个响应 message MyResponse { int32 statusCode = 1; Person person = 2; } // 编译一个RPC服务 service PersonService { // 定义一个方法getPeronById,传入MyRequest,返回MyResponse rpc getPersonById (MyRequest) returns (MyResponse) { } // 定义一个方法getPersons,传入MyRequest,返回多个MyResponse(同理,你还可以发送多个Request) rpc getPersons (MyRequest) returns (stream MyResponse) { } }
- 编译*.proto文件,转化为语言源文件
- 在main目录下创建proto文件夹,将my_protocol.proto文件放入其中
- 执行命令 mvn compile
- maven会自动寻找main/proto/下的*.proto文件,进行编译转换
- 生成的class文件存放在target/classs/下
- 生成的源文件存放在target/generated-sources/下
3. 使用 gRPC 编写服务端/客户端
- 引入Maven依赖(当前版本 1.25.0)
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.25.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.25.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.25.0</version> </dependency>
- 服务端示例
- PersonServiceImpl.java
package com.skey.grpcdemo; import com.skey.grpcdemo.grpc.MyRequest; import com.skey.grpcdemo.grpc.MyResponse; import com.skey.grpcdemo.grpc.Person; import com.skey.grpcdemo.grpc.PersonServiceGrpc; import io.grpc.stub.StreamObserver; /** * Description: 服务实现类 * <br/> * Date: 2019/12/18 22:03 * * @author ALion */ public class PersonServiceImpl extends PersonServiceGrpc.PersonServiceImplBase { @Override public void getPersonById(MyRequest request, StreamObserver<MyResponse> responseObserver) { System.out.println("PersonServiceImpl.getPersonById"); MyResponse.Builder builder = MyResponse.newBuilder(); int id = request.getId(); if (id > 105) { // 如果id大于,返回失败的状态码0 builder.setStatusCode(0); } else { Person person = Person.newBuilder() .setId(id) .setName("laowang") .setAge(28) .build(); builder.setStatusCode(1).setPerson(person); } responseObserver.onNext(builder.build()); // 消息发送完成 responseObserver.onCompleted(); } @Override public void getPersons(MyRequest request, StreamObserver<MyResponse> responseObserver) { System.out.println("PersonServiceImpl.getPersons"); for (int i = 0; i < 5; i++) { Person person = Person.newBuilder() .setId(i) .setName("laowang") .setAge(28) .build(); MyResponse response = MyResponse.newBuilder() .setStatusCode(1) .setPerson(person) .build(); responseObserver.onNext(response); } responseObserver.onCompleted(); } }
- ServerDemo.java
package com.skey.grpcdemo; import io.grpc.Server; import io.grpc.ServerBuilder; /** * Description: 服务端示例 * <br/> * Date: 2019/12/18 22:15 * * @author ALion */ public class ServerDemo { public static void main(String[] args) { // 构建Server Server server = ServerBuilder.forPort(10086) .addService(new PersonServiceImpl()) .build(); try { // 启动 server.start(); // 阻塞Server server.awaitTermination(); } catch (Exception e) { e.printStackTrace(); } } }
- PersonServiceImpl.java
- 客户端示例
- ClientDemo.java
package com.skey.grpcdemo; import com.skey.grpcdemo.grpc.MyRequest; import com.skey.grpcdemo.grpc.MyResponse; import com.skey.grpcdemo.grpc.PersonServiceGrpc; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import java.util.Iterator; /** * Description: 客户端示例 * <br/> * Date: 2019/12/18 22:15 * * @author ALion */ public class ClientDemo { public static void main(String[] args) { // 构建客户端 ManagedChannel managedChannel = ManagedChannelBuilder .forAddress("localhost",10086) .usePlaintext() .build(); PersonServiceGrpc.PersonServiceBlockingStub blockingStub = PersonServiceGrpc.newBlockingStub(managedChannel); for (int i = 100; i < 107; i++) { // 构建Request MyRequest request = MyRequest.newBuilder() .setId(i) .build(); // 发送Request,获得Response MyResponse response = blockingStub.getPersonById(request); // 解析状态码 if (response.getStatusCode() == 1) { System.out.println(response.getPerson()); } else { System.out.println("No such person that id = " + i); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("------------------------------------------"); // 返回多个 MyResponse MyRequest request = MyRequest.newBuilder() .setId(1) .build(); Iterator<MyResponse> responseIter = blockingStub.getPersons(request); responseIter.forEachRemaining(System.out::println); } }