gRPC 是 Google 开源的通用高性能 RPC 框架,它支持的是使用Protocol Buffers来编写 Service 定义,支持较多语言扩平台并且拥有强大的二进制序列化工具集。与文章《 RPC 框架实践之:Apache Thrift 》 一文中实践的另一种通用 RPC 框架 Thrift 能通过 Generator 自动生成对应语言的 Service 接口类似,gRPC 也能 自动地生成 Server 和 Client 的 Service 存根( Stub ),我们只需要 一个命令 就能快速搭建起 RPC 运行环境。
下面实践一下 gRPC 框架,做的事情就是:Client 端通过远程 RPC 调用 Server 的获取时间的接口,从而将服务器时间获取到本地并显示。
类似于之前对于 RPC 框架: Thrift 的实践步骤,下面一一阐述。
首先创建一个基于 Maven 的项目: GrpcAPI
pom 中加入 grpc 相关的依赖
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.12.0</version>
</dependency>
这个 grpc-all 包含了很多 grpc 相关的组件:grpc-netty、grpc-protobuf、grpc-stub 等等
这里添加两个 Maven 插件,目的是后面需要用这些插件来执行 Protocol Buffers 命令,从而自动生成相关的 Stub 代码:
os-maven-plugin
:生成平台无关的属性
protobuf-maven-plugin
:执行 Protocol Buffers 命令并生成 Stub 代码库
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.1.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<pluginId>grpc-java</pluginId>
<protocArtifact>com.google.protobuf:protoc:3.0.2:exe:${os.detected.classifier}</protocArtifact>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.2.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
这里.proto 文件的作用和写法就和我的前一篇文章《 RPC 框架实践之:Apache Thrift 》 一文中 Thrift 所要求的.thrift 文件编写一样,是有其自己的语法要求的!
syntax = "proto3 ”; // 语法版本
// stub 选项
option java_package = "com.hansonwang99.grpc.api ”;
option java_outer_classname = “ RPCDateServiceApi ”;
option java_multiple_files = true;
// 定义包名,类似于我的文章《 RPC 框架实践之:Apache Thrift 》中的 Thrift 的 namespace
package com.hansonwang99.grpc.api;
// 服务接口定义,服务端和客户端都要遵守该接口进行通信
service RPCDateService {
rpc getDate (RPCDateRequest) returns (RPCDateResponse) {}
}
// 定义消息(请求)
message RPCDateRequest {
string userName = 1;
}
// 定义消息(响应)
message RPCDateResponse {
string serverDate = 1;
}
mvn compile
命令来自动生成代码 Stubmvn 编译完成以后,在target/generated-sources
目录下就能看到根据上面.proto
文件自动转化生成的Java 代码 Stub
代码生成结果如下所示
好了,既然 gRPC-API 已经有了,下面可以分别编写服务端和客户端
创建基于 Maven 的项目:Server
pom 中添加 GrpcAPI 依赖
<dependency>
<groupId>com.hansonwang99</groupId>
<artifactId>GrpcAPI</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
接下来一步比较关键
public class RPCDateServiceImpl extends RPCDateServiceGrpc.RPCDateServiceImplBase{
@Override
public void getDate(RPCDateRequest request, StreamObserver<RPCDateResponse> responseObserver) {
RPCDateResponse rpcDateResponse = null;
Date now=new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("今天是"+"yyyy 年 MM 月 dd 日 E kk 点 mm 分”);
String nowTime = simpleDateFormat.format( now );
try {
rpcDateResponse = RPCDateResponse
.newBuilder()
.setServerDate( "Welcome " + request.getUserName() + ", " + nowTime )
.build();
} catch (Exception e) {
responseObserver.onError(e);
} finally {
responseObserver.onNext( rpcDateResponse );
}
responseObserver.onCompleted();
}
}
我想此处重写的getDate()
方法并不陌生吧,这正是上文 .proto 文件中定义的 Service 接口。
此处逻辑比较简单:获取当前时间,并且将其与请求RPCDateRequest
中提取出的userName
字段进行拼接,然后返回给调用端!形成一个闭环
public class GRPCServer {
private static final int port = 9999;
public static void main( String[] args ) throws Exception {
Server server = ServerBuilder.
forPort(port)
.addService( new RPCDateServiceImpl() )
.build().start();
System.out.println( "grpc 服务端启动成功, 端口=" + port );
server.awaitTermination();
}
}
端口自定义的 9999,也就是在该端口监听。现在可以立即运行 GRPCServer,来启动服务端
创建基于 Maven 的项目:Client
pom 中依然需要添加 GrpcAPI 依赖
<dependency>
<groupId>com.hansonwang99</groupId>
<artifactId>GrpcAPI</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
public class GRPCClient {
private static final String host = “ localhost ”;
private static final int serverPort = 9999;
public static void main( String[] args ) throws Exception {
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress( host, serverPort ).usePlaintext().build();
try {
RPCDateServiceGrpc.RPCDateServiceBlockingStub rpcDateService = RPCDateServiceGrpc.newBlockingStub( managedChannel );
RPCDateRequest rpcDateRequest = RPCDateRequest
.newBuilder()
.setUserName(“ hansonwang99 ”)
.build();
RPCDateResponse rpcDateResponse = rpcDateService.getDate( rpcDateRequest );
System.out.println( rpcDateResponse.getServerDate() );
} finally {
managedChannel.shutdown();
}
}
}
现在立即启动 GRPCClient !
还记得我们的目标吗?
RPC 完成的即是远程的过程调用,在本实验中那就是客户端可以远程调用服务端的 getDate()过程,并将结果取到客户端来显示!
本文实验代码在此 → 需要自取
作者更多的原创文章:在 V2EX
作者其他一些 RPC 框架的实践如下:
扩展阅读:
1
virusdefender 2018-05-21 07:07:54 +08:00
代码中中英文的引号都能错,真的测试运行过么?
|
2
hansonwang99 OP @virusdefender 哪地方错了?
|
3
hansonwang99 OP @virusdefender proto 里可能是粘贴的原因,源码去我码云上取
|
4
6diyipi 2018-05-21 09:09:00 +08:00
这桌面秀的。
|
5
hansonwang99 OP @6diyipi 小弟不敢
|
6
cloverstd 2018-05-21 09:46:09 +08:00
显示器啥型号,底下的底座是自带的吗
|
7
SouthCityCowBoy 2018-05-21 20:51:50 +08:00
大佬
|