Spring Boot 中使用 grpc 入门
grpc 简介
grpc 是什么
grpc 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。
grpc 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
环境安装
首先安装 protobuf :
基于MAC环境,打开终端,执行如下命令:brew install protobuf
查看是否安装成功:
protoc --version
再编译安装 grpc-java 插件:
使用git下载源码:git clone https://github.com/grpc/grpc-java.git
进入源码 compiler 目录:
cd compiler
依次执行命令:
../gradlew java_pluginExecutable ../gradlew test ../gradlew install
可能需要翻墙,并执行成功为止,最后会生成插件 protoc-gen-grpc-java 。
使用示例
Maven 依赖
在服务端和客户端的 pom.xml 中添加相关依赖:
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>1.12.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.12.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-core</artifactId> <version>1.12.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.12.0</version> </dependency>
编写服务端 proto 文件
hello.proto
syntax = "proto3"; option java_multiple_files = false; option java_package = "com.hans.grpcserver.grpc"; option java_outer_classname = "HelloProto"; package hello; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
使用 proto 工具生成 java 代码
protoc --java_out=. hello.proto
使用 grpc-java 工具生成 java 代码
注意插件地址为以上编译生成的实际地址
protoc --plugin=protoc-gen-grpc-java=/Users/huangxun/workspace/java/grpc-java/compiler/build/exe/java_plugin/protoc-gen-grpc-java --grpc-java_out=. --proto_path=. hello.proto
编写服务端 proto 文件
修改 option java_package = "com.hans.grpcclient.grpc"; 后再次执行以上命令则生成客户端 java 代码
将代码放到对应目录
即 com.hans.grpcserver 子目录 grpc 下
编写服务端
package com.hans.grpcserver.grpc.server; import com.hans.grpcserver.grpc.GreeterGrpc; import com.hans.grpcserver.grpc.HelloProto.HelloReply; import com.hans.grpcserver.grpc.HelloProto.HelloRequest; import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver; import java.io.IOException; import java.util.logging.Logger; public class HelloServer { private static final Logger logger = Logger.getLogger(HelloServer.class.getName()); private int port = 50051; private Server server; private void start() throws IOException { // 使用ServerBuilder来构建和启动服务,通过使用forPort方法来指定监听的地址和端口 // 创建一个实现方法的服务GreeterImpl的实例,并通过addService方法将该实例纳入 // 调用build() start()方法构建和启动rpcserver 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"); HelloServer.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 HelloServer server = new HelloServer(); server.start(); server.blockUntilShutdown(); } // 我们的服务GreeterImpl继承了生成抽象类GreeterGrpc.GreeterImplBase,实现了服务的所有方法 private class GreeterImpl extends GreeterGrpc.GreeterImplBase { @Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); // 使用响应监视器的onNext方法返回HelloReply responseObserver.onNext(reply); // 使用onCompleted方法指定本次调用已经完成 responseObserver.onCompleted(); } } }
编写客户端
package com.hans.grpcclient.grpc.client; import com.hans.grpcclient.grpc.GreeterGrpc; import com.hans.grpcclient.grpc.HelloProto.HelloReply; import com.hans.grpcclient.grpc.HelloProto.HelloRequest; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; public class HelloClient { private static final Logger logger = Logger.getLogger(HelloClient.class.getName()); private final ManagedChannel channel; private final GreeterGrpc.GreeterBlockingStub blockingStub; /** Construct client connecting to HelloWorld server at {@code host:port}. */ // 首先,我们需要为stub创建一个grpc的channel,指定我们连接服务端的地址和端口 // 使用ManagedChannelBuilder方法来创建channel public HelloClient(String host, int port) { channel = ManagedChannelBuilder.forAddress(host, port) // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid // needing certificates. .usePlaintext(true) .build(); // 使用我们从proto文件生成的GreeterGrpc类提供的newBlockingStub方法指定channel创建stubs 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 + " ..."); // 创建并定制protocol buffer对象,使用该对象调用服务端的sayHello方法,获得response HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloReply response; try { response = blockingStub.sayHello(request); // 如果有异常发生,则异常被编码成Status,可以从StatusRuntimeException异常中捕获 } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } logger.info("Greeting: " + response.getMessage()); } /** * Greet server. If provided, the first element of {@code args} is the name to use in the * greeting. */ public static void main(String[] args) throws Exception { HelloClient client = new HelloClient("localhost", 50051); try { /* Access a service running on the local machine on port 50051 */ String user = "hans"; if (args.length > 0) { user = args[0]; /* Use the arg as the name to greet if provided */ } client.greet(user); } finally { client.shutdown(); } } }
启动服务端
后台打印输出:
Server started, listening on 50051
执行客户端
后台打印输出:
Will try to greet hans ... Greeting: Hello hans
Github 完整代码
相关推荐
darren0zdc 2020-10-16
ltstud 2020-07-24
Erick 2020-07-18
wujingsheng0 2020-06-16
xmwang0 2020-06-14
极品小肥羊 2020-05-31
小小书童 2020-05-20
极品小肥羊 2020-04-23
小小书童 2020-04-10
君小黑 2020-03-04
naiwenw 2020-02-18
小小书童 2020-02-22
dabaoge 2020-02-16
小小书童 2019-12-23
dabaoge 2020-01-25
MAC2007 2020-01-17
duanlove技术路途 2019-12-28