gRPC + protobuf + idea + maven + Java Client/Server实践

RPC(Remote Procedure Call)是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

之前本人介绍过Java简单实现RPC的例子,这里将继续介绍如何快速使用工业级别的RPC技术gRPC。

gRPC是谷歌搞的一个RPC协议,它配套protobuf使用。用户可以通过protobuffer自定义传输数据的格式。

使用过程可以概述为三点:

  • 在.proto文件中定义服务。
  • 使用协议缓冲区编译器生成服务器和客户端代码。
  • 使用Java gRPC API为您的服务编写一个简单的客户端和服务器

在这里插入图片描述

  1. 新建maven项目,并导入pom文件

    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty-shaded</artifactId>
      <version>1.23.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-protobuf</artifactId>
      <version>1.23.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.23.0</version>
    </dependency>
    
    <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.23.0:exe:${os.detected.classifier}</pluginArtifact>
          </configuration>
          <executions>
            <execution>
              <goals>
                <goal>compile</goal>
                <goal>compile-custom</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    
  2. 新建proto文件

    syntax = "proto3";
    
    package com.chenqh.proto;
    
    // 生成代码所在包
    option java_package = "com.chenqh.proto";
    // 生成代码类名
    option java_outer_classname = "StudentProto";
    option java_multiple_files = true;
    
    service StudentService{
        rpc GetRealNameByUsername(MyRequest) returns (MyResponse){}
    }
    
    message MyRequest {
        string username = 1;
    }
    message MyResponse {
        string realname = 2;
    }
    
  3. 执行命令mvn generate-sources

    生成接口如下所示

  4. 服务端实现接口

    package grpc;
    
    import com.chenqh.proto.MyRequest;
    import com.chenqh.proto.MyResponse;
    import com.chenqh.proto.StudentServiceGrpc;
    import io.grpc.stub.StreamObserver;
    
    public class StudentServiceImpl extends StudentServiceGrpc.StudentServiceImplBase {
        @Override
        public void getRealNameByUsername(MyRequest request, StreamObserver<MyResponse> responseObserver) {
            System.out.println("has received information from client : "+ request.getUsername());
            responseObserver.onNext(MyResponse.newBuilder().setRealname("proto response").build());
            responseObserver.onCompleted();
        }
    }
    
   package grpc;
   
   import io.grpc.ServerBuilder;
   import io.grpc.Server;
   
   import java.io.IOException;
   
   public class GrpcServer {
       private Server server;
   
       private void start() throws IOException {
           /* The port on which the server should run */
           int port = 8899;
           server = ServerBuilder.forPort(port)
                   .addService(new StudentServiceImpl())
                   .build()
                   .start();
           // 回调钩子
           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");
                   GrpcServer.this.stop();
                   System.err.println("*** server shut down");
               }
           });
       }
       private void stop() {
           if (server != null) {
               server.shutdown();
           }
       }
   
       private void awaitTermination() throws InterruptedException {
           if(null != this.server){
               this.server.awaitTermination();
           }
       }
   
       public static void main(String[] args) throws InterruptedException, IOException {
           GrpcServer server = new GrpcServer();
           server.start();
           server.awaitTermination();
       }
   }
   
  1. 客户端调用接口

    package grpc;
    
    
    import com.chenqh.proto.MyRequest;
    import com.chenqh.proto.MyResponse;
    import com.chenqh.proto.StudentServiceGrpc;
    import io.grpc.ManagedChannel;
    import io.grpc.ManagedChannelBuilder;
    
    import java.util.concurrent.TimeUnit;
    
    public class Client {
        public static void main(String[] args) throws InterruptedException {
            ManagedChannel managedChannel = ManagedChannelBuilder
                    .forAddress("localhost",8899).usePlaintext(true).build();
            StudentServiceGrpc.StudentServiceBlockingStub blockingStub =
                    StudentServiceGrpc.newBlockingStub(managedChannel);
            //服务端返回单条消息
            MyResponse myResponse = blockingStub.
                    getRealNameByUsername(MyRequest.newBuilder().setUsername("proto  request").build());
            System.out.println(myResponse.getRealname());
            managedChannel.shutdown().awaitTermination(3, TimeUnit.SECONDS);
    
        }
    }
    
  2. 启动服务端

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wAg1yklO-1571816882893)(C:\Users\cqh_d\AppData\Roaming\Typora\typora-user-images\1571811956049.png)]

  3. 启动客户端

在这里插入图片描述
在这里插入图片描述


版权声明:本文为qq_28420973原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。