gRPC Java:快速开始和项目原型

栏目: 服务器 · 发布时间: 7年前

内容简介:gRPC Java:快速开始和项目原型

之前一直用 Go 来写gRPC的服务,简单而直接。最近工作涉及用 Java 开发几个gRPC的服务,我们知道Java中有很多框架和Magical,所以这几个服务还是希望以Java的风格来写,因此打算写几篇文章对此做个整理。本篇做为开篇 ,先简单从快速开始一个项目原型开始写起。

开发环境

  • JDK 1.8
  • gradle 3.5
  • gRPC 1.30
  • protobuf 3.2.0

初始化项目原型

新建项目目录 grpc-java-demo

mkdir grpc-java-demo

使用gradle生成项目原型:

cd grpc-java-demo
gradle init --type=java-application

修改生成构建脚本build.gradle:

apply plugin: 'java'
apply plugin: 'com.google.protobuf'
apply plugin: 'eclipse'

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
  }
}

repositories {
   mavenCentral()
}

sourceSets {
   main {
    java {
        srcDir 'build/generated/source/proto/main/java'
        srcDir 'build/generated/source/proto/main/grpc'
    }
   }
}

compileJava {
    sourceCompatibility=1.8
    targetCompatibility=1.8
    options.encoding='UTF-8'
}
compileTestJava {
    sourceCompatibility=1.8
    targetCompatibility=1.8
    options.encoding='UTF-8'
}

configurations { 
    all*.exclude group:'com.sun.xml.bind',module:'jaxb-impl'
    all*.exclude group:'xml-apis',module:'xml-apis'
    all*.exclude group:'stax',module:'stax-api'
    all*.exclude group:'org.slf4j',module:'slf4j-log4j12'
    all*.exclude group:'commons-logging'
}

ext {
    grpcVersion= '1.3.0'
    logbackVersion = '1.2.2'
    slf4jVersion='1.7.25'
}

dependencies {
    compile "io.grpc:grpc-netty:${grpcVersion}"
    compile "io.grpc:grpc-protobuf:${grpcVersion}"
    compile "io.grpc:grpc-stub:${grpcVersion}"

    compile "org.slf4j:slf4j-api:$slf4jVersion"
    compile "ch.qos.logback:logback-classic:$logbackVersion"
    runtime "org.slf4j:jcl-over-slf4j:$slf4jVersion"
    runtime "org.slf4j:log4j-over-slf4j:$slf4jVersion"
    runtime "org.slf4j:jul-to-slf4j:$slf4jVersion"
    testCompile 'junit:junit:4.12'
}

protobuf {
  protoc {
    artifact = 'com.google.protobuf:protoc:3.2.0'
  }
  plugins {
    grpc {
      artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
    }
  }
  generateProtoTasks {
    all()*.plugins {
      grpc {
        option 'enable_deprecated=false'
      }
    }
  }
}

tasks.eclipse.dependsOn compileJava

新建src/main/resources目录,在目录下创建logback的配置文件logback.xml:

<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false" scan="false" scanPeriod="30 seconds">

  <contextName>grpc-java-demo</contextName>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        <![CDATA[
        [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] %level %logger - %message%n
        ]]>
      </pattern>
    </encoder>
  </appender>

  <logger name="com.frognew.grpc.demo" level="INFO"  additivity="false">
    <appender-ref ref="STDOUT" />
  </logger>

  <root level="WARN">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

删除src/main/java下的App.java文件和src/test/java下的AppTest.java文件。在src下新建名称为proto的源码目录,在此目录中新建helloworld.proto文件内容如下:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.frognew.grpc.demo.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

运行 gradle eclipse 生成eclipse项目,此过程中会调用gradle的 com.google.protobuf 插件基于src/main/proto中的PB文件生成Java代码。将生成的项目导入eclipse中。

gRPC Java:快速开始和项目原型

后续开发过程中,当PB文件发生修改时,只需要执行 gradle eclipse 再刷新eclipse项目即可。

HelloWorldServer和HelloWorldClient

基于官方demo中的代码进行修改:

com.frognew.grpc.demo.helloworld.HelloWorldServer.java:

package com.frognew.grpc.demo.helloworld;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;

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

com.frognew.grpc.demo.helloworld.HelloWorldClient.java:

package com.frognew.grpc.demo.helloworld;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;

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.warn("RPC failed: {}", 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 {
        HelloWorldClient client = new HelloWorldClient("localhost", 50051);
        try {
          /* Access a service running on the local machine on port 50051 */
          String user = "world";
          if (args.length > 0) {
            user = args[0]; /* Use the arg as the name to greet if provided */
          }
          client.greet(user);
        } finally {
          client.shutdown();
        }
      }
}

运行Server输出:

Server started, listening on 50051

运行Client,向Server发送RPC请求,输出:

Will try to greet world ...
Greeting: Hello world

总结

本篇主要是根据gRPC Java官方示例代码演示怎么快速使用Gradle快速创建gRPC Java项目的框架原型,因为gRPC HelloWorld的代码十分简单,就不展开多写了。

参考


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序设计抽象思想

程序设计抽象思想

Eric S.Roberts、闪四清 / 闪四清 / 清华大学出版社 / 2005-6 / 78.00元

本书全面介绍了数据结构的基础内容。介绍了多个库包,可用于简化编程流程;详细讨论了递归编程的用法,包括大量难度各异的编程示例和练习。一起来看看 《程序设计抽象思想》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具