1. 概念
gRPC的定义:
- 一个高性能、通用的开源RPC框架
- 主要面向移动应用开发: gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。
- 基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发
- 支持众多开发语言
2. Hello world Demo
主要流程:
1. 通过.proto文件定义服务
2. 通过protocol buffer compiler插件生成客户端和服务端
3. 通过grpc API生成客户端和服务端代码
2.1 定义RPC服务 proto
// 如果使用此注释,则使用proto3; 否则使用proto2
syntax = "proto3";
// 生成类的包名
option java_package = "com.hry.spring.grpc.simple";
//生成的数据访问类的类名,如果没有指定此值,则生成的类名为proto文件名的驼峰命名方法
option java_outer_classname = "GreeterEntity";
option java_multiple_files = true;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
2.2 生成基础类
通过proto里的方法生成基础类
通过Protobuf3 的第一个Java demo的步骤生成protobuf3相关代码,如HelloReply,HelloReplyOrBuilder,HelloRequest,HelloRequestOrBuilder,详细见 github代码
生成GreeterGrpc
a. 配置pom.xml,指定proto文件
<!-- grpc 依赖jar -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.3.0</version>
</dependency>
<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.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 根据proto文件生成java -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.2.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.3.0:exe:${os.detected.classifier}</pluginArtifact>
<protoSourceRoot>src/main/resources/com/hry/spring/grpc/simple/</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
b. 执行pom.xml,在target/generated-sources/protobuf/grpc-java/com/hry/spring/grpc/simple/ 目录GreeterGrpc.java
GreeterGrpc封装基本的GRPC功能,后续的客户端和服务端都从这个类引申出来。GreeterGrpc类见gibhub
2.3 服务端
服务端代码
public class HelloWorldServer {
private static final Logger logger = LoggerFactory.getLogger(HelloWorldServer.class);
private Server server;
private void start() throws IOException {
/* The port on which the server should run */
int port = 50051;
server = ServerBuilder.forPort(port).addService(new GreeterImpl()).build().start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
// Use stderr here since the logger may have been reset by its
// JVM shutdown hook.
System.err.println("*** shutting down gRPC server since JVM is shutting down");
HelloWorldServer.this.stop();
System.err.println("*** server shut down");
}
});
}
private void stop() {
if (server != null) {
server.shutdown();
}
}
/**
* Await termination on the main thread since the grpc library uses daemon
* threads.
*/
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
/**
* Main launches the server from the command line.
*/
public static void main(String[] args) throws IOException, InterruptedException {
final HelloWorldServer server = new HelloWorldServer();
server.start();
server.blockUntilShutdown();
}
static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
}
2.4 客户端
客户端主代码
public class HelloWorldClient {
private static final Logger logger = LoggerFactory.getLogger(HelloWorldClient.class);
private final ManagedChannel channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
/**
* Construct client connecting to HelloWorld server at {@code host:port}.
*/
public HelloWorldClient(String host, int port) {
this(ManagedChannelBuilder.forAddress(host, port)
// Channels are secure by default (via SSL/TLS). For the example
// we disable TLS to avoid
// needing certificates.
.usePlaintext(true));
}
/**
* Construct client for accessing RouteGuide server using the existing
* channel.
*/
HelloWorldClient(ManagedChannelBuilder<?> channelBuilder) {
channel = channelBuilder.build();
blockingStub = GreeterGrpc.newBlockingStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
/** Say hello to server. */
public void greet(String name) {
logger.info("Will try to greet " + name + " ...");
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloReply response;
try {
response = blockingStub.sayHello(request);
} catch (StatusRuntimeException e) {
logger.error("RPC failed: {0}", e.getStatus());
return;
}
logger.info("Greeting: " + response.getMessage());
}
public static void main(String[] args) throws Exception {
HelloWorldClient client = new HelloWorldClient("localhost", 50051);
try {
String user = "world";
if (args.length > 0) {
user = args[0];
}
client.greet(user);
} finally {
client.shutdown();
}
}
}
2.4 运行
先运行服务端,再运行客户端,关键日志打印如下:
21:35:35.208 [main] INFO com.hry.spring.grpc.simple.HelloWorldClient - Will try to greet world ...
21:35:35.847 [main] INFO com.hry.spring.grpc.simple.HelloWorldClient - Greeting: Hello world