grpc-java入门实例

本文主要介绍如何在Intellij IDEA环境下,快速搭建出grpc-java的入门实例。这个入门实例是一个HelloWorld程序,客户端发送world到服务端,服务端接收到请求后,拼装成 Hello,world返回。

环境配置
JDK1.8
Maven 3.6
Intellij IDEA

创建一个Project

使用Maven自带的maven-archetype-webapp原型创建一个webapp项目,在src/main下新建对应的java和proto文件夹,并将java文件夹转换为 Source Root,项目结构如下图所示:
grpc-java入门实例_第1张图片

pom文件中引入相关依赖和插件

	
		io.grpc
		grpc-netty-shaded
    	1.27.2
	
	
    	io.grpc
    	grpc-protobuf
    	1.27.2
	
	
    	io.grpc
        grpc-stub
        1.27.2
	
	
        grpc-java
        
            
                kr.motd.maven
                os-maven-plugin
                1.6.2
            
        
        
            
                org.xolstice.maven.plugins
                protobuf-maven-plugin
                0.6.1
                
                    com.google.protobuf:protoc:3.11.0:exe:${os.detected.classifier}
                    grpc-java
                    io.grpc:protoc-gen-grpc-java:1.27.2:exe:${os.detected.classifier}
                
                
                    
                        
                            compile
                            compile-custom
                        
                    
                
            
        
    

编写.proto文件,定义服务接口

在proto文件夹下编写一个helloworld.proto文件,内容如下:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

通过protocol buffer编译器生成服务端和客户端代码

选中Project,执行Maven Compile操作,会在target/generate-sources下生成对应的代码。
grpc-java入门实例_第2张图片

使用Java gRPC API为上面定义的服务接口编写客户端和服务端

在src/main/java文件夹下新建,io.grpc.examples.helloworldPackage,并将代码放在此文件夹下,与helloworld.proto文件中指定的java_package参数对应。(如果放在其它文件夹下,代码要做适当调整,因为代码的引用位置变了)。

客户端代码
HelloWorldClient.java

public class HelloWorldClient {
  private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());

  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()
        .build());
  }

  /** Construct client for accessing HelloWorld server using the existing channel. */
  HelloWorldClient(ManagedChannel channel) {
    this.channel = channel;
    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.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 {
    // Access a service running on the local machine on port 50051
    HelloWorldClient client = new HelloWorldClient("localhost", 50051);
    try {
      String user = "world";
      // Use the arg as the name to greet if provided
      if (args.length > 0) {
        user = args[0];
      }
      client.greet(user);
    } finally {
      client.shutdown();
    }
  }
}

服务端代码
HelloWorldServer.java

public class HelloWorldServer {
  private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());

  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");
        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);
    }
  }

  /**
   * 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 responseObserver) {
      HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }
  }
}

执行代码

先运行HelloWorldServer,再运行HelloWorldClient,结果如下:
grpc-java入门实例_第3张图片
grpc-java入门实例_第4张图片
有兴趣的话可以改改这个示例,然后看看运行效果。

注意:
如果想在Eclipse环境运行该实例,需要注意以下几个不同点:

  1. pom文件中插件引用
    Intellij中:
	
    	
    		kr.motd.maven
    		os-maven-plugin
    		1.6.2
     	
     

eclipse中:

	
		kr.motd.maven
		os-maven-plugin
		1.6.1
		
			
			initialize
			
				detect
			
		
		
	
  1. .proto文件经过IDE编译后生成的代码引用问题
    Intellij中可以直接引用target目录下生成的protobuf代码,eclipse下不行,需要将生成的文件copy到src/main/java对应的文件夹下(和.proto中配置的java_package参数一致)。另外,因为jdk编译版本的问题,文件copy过后,需要去掉一些@java.lang.Override,否则代码报错(网上查阅资料,jdk高与1.6版本后就会有这个问题,具体没有测试过)。

参考资料
gRPC Quick Start
grpc-java源码地址

------------本文结束感谢您的阅读------------

你可能感兴趣的:(RPC)