🌀grpc-java单向RPC实例 | 字数总计: 1.4k | 阅读时长: 7分钟 | 阅读量: |
这篇文章将介绍如何使用grpc-java
开发一个简单的单向RPC
服务。
引入依赖 新建一个maven
项目,按照官网的示例,pom.xml
中需添加以下依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.43.1</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.43.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.43.1</version> </dependency> <dependency> <!-- necessary for Java 9+ --> <groupId>org.apache.tomcat</groupId> <artifactId>annotations-api</artifactId> <version>6.0.53</version> <scope>provided</scope> </dependency>
然后添加protoc
的maven
插件:
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 <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</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.19.1:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.43.1:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
接下来我们就可以通过编写.proto
文件来定义rpc
接口和数据类型,默认情况下.proto
文件需放置在src/main/proto
和src/test/proto
目录中(如没有则相应新建文件夹)。
编写.proto
文件 下面编写一个helloworld.proto
文件定义一个简单的rpc
服务,.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 syntax = "proto3"; // 为每个Java类生成单独的.java文件 option java_multiple_files = true; // 生成的Java包名 option java_package = "org.sunchaser.sparrow.javaee.grpc.core.helloworld"; // 生成的Java类名 option java_outer_classname = "HelloWorldProto"; // 指定Java包名,被option java_package选项覆盖 package helloworld; // 定义rpc服务 service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } // 定义message message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
以上就定义了一个简单rpc
,客户端使用存根发送请求到服务端并等待响应返回,就像调用本地方法一样调用rpc
服务。定义了一个SayHello rpc
服务,入参HelloRequest
,返参HelloReply
。
生成grpc
及protobuf
相关类 1 2 mvn protobuf:compile mvn protobuf:compile-custom
使用IDEA
的maven
插件快速执行以上命令,在target
目录下可看到生成的相关类如下图所示。
编写grpc
服务端 编写HelloWorldServer
服务端如下:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package org.sunchaser.sparrow.javaee.grpc.core.helloworld;import io.grpc.Server;import io.grpc.ServerBuilder;import io.grpc.stub.StreamObserver;import java.io.IOException;import java.util.concurrent.TimeUnit;import java.util.logging.Logger;public class HelloWorldServer { private static final Logger log = Logger.getLogger(HelloWorldServer.class.getName()); private Server server; private void start () throws IOException { int port = 50051 ; server = ServerBuilder.forPort(port) .addService(new GreeterImpl ()) .build() .start(); log.info("GRPC Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread (() -> { System.err.println("*** shutting down gRPC server since JVM is shutting down" ); try { HelloWorldServer.this .stop(); } catch (InterruptedException e) { e.printStackTrace(System.err); } System.err.println("*** server shut down" ); })); } private void stop () throws InterruptedException { if (server != null ) { server.shutdown().awaitTermination(30 , TimeUnit.SECONDS); } } private void blockUntilShutdown () throws InterruptedException { if (server != null ) { server.awaitTermination(); } } 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 request, StreamObserver<HelloReply> responseObserver) { HelloReply helloReply = HelloReply.newBuilder() .setMessage("Hello " + request.getName()) .build(); responseObserver.onNext(helloReply); responseObserver.onCompleted(); } } }
运行main
方法后控制台输出:
1 2 一月 17, 2022 2:25:39 下午 HelloWorldServer start 信息: GRPC Server started, listening on 50051
编写grpc
客户端 编写HelloWorldClient
客户端如下:
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 package org.sunchaser.sparrow.javaee.grpc.core.helloworld;import io.grpc.Channel;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 HelloWorldClient { private static final Logger log = Logger.getLogger(HelloWorldClient.class.getName()); private final GreeterGrpc.GreeterBlockingStub blockingStub; public HelloWorldClient (Channel channel) { blockingStub = GreeterGrpc.newBlockingStub(channel); } public void greet (String name) { log.info("Will try to greet " + name + " ..." ); HelloRequest request = HelloRequest.newBuilder() .setName(name) .build(); HelloReply response; try { response = blockingStub.sayHello(request); } catch (StatusRuntimeException e) { log.log(Level.WARNING, "gRPC failed: {0}" , e.getStatus()); return ; } log.info("Greeting: " + response.getMessage()); } public static void main (String[] args) throws InterruptedException { String user = "grpc" ; String target = "localhost:50051" ; if (args.length > 0 ) { if ("--help" .equals(args[0 ])) { System.err.println("Usage: [name [target]]" ); System.err.println("" ); System.err.println(" name The name you wish to be greeted by. Defaults to " + user); System.err.println(" target The server to connect to. Defaults to " + target); System.exit(1 ); } user = args[0 ]; } if (args.length > 1 ) { target = args[1 ]; } ManagedChannel channel = ManagedChannelBuilder.forTarget(target) .usePlaintext() .build(); try { HelloWorldClient client = new HelloWorldClient (channel); client.greet(user); } finally { channel.shutdownNow().awaitTermination(5 , TimeUnit.SECONDS); } } }
可通过main
方法的启动参数传入user
和target
,默认user="grpc";target="localhost:50051"
表示,调用刚才我们编写好的服务端,运行main
方法后控制台输出如下:
1 2 3 4 一月 17, 2022 2:31:23 下午 HelloWorldClient greet 信息: Will try to greet grpc ... 一月 17, 2022 2:31:24 下午 HelloWorldClient greet 信息: Greeting: Hello grpc
可以看到已经完成了一次远程rpc
服务调用。