内容简介: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中。
后续开发过程中,当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元
本书全面介绍了数据结构的基础内容。介绍了多个库包,可用于简化编程流程;详细讨论了递归编程的用法,包括大量难度各异的编程示例和练习。一起来看看 《程序设计抽象思想》 这本书的介绍吧!