使用grpc可以用来进行不同系统之间的信息交互,而且grpc不限于java,使用同一个proto文件可以在不同的编程语言之间交互。

上面这张图介绍了proto文件的语法,对应proto3.0,具体更多的内容请参考文档:
http://www.grpc.io/docs/#generating-grpc-code
?
?
下面我们先讲一下如何在java中通过proto文件生成java代码,然后再讲如何使用。
添加如下依赖与插件:
- <dependency>??
- ????<groupId>io.grpc</groupId>??
- ????<artifactId>grpc-all</artifactId>??
- ????<version>0.14.0</version>??
- </dependency>??
- <dependency>??
- ????<groupId>com.google.protobuf</groupId>??
- ????<artifactId>protobuf-java</artifactId>??
- ????<version>3.0.0-beta-2</version>??
- </dependency>??
- ??
- ??
- ????<build>??
- ????????<extensions>??
- ????????????<extension>??
- ????????????????<groupId>kr.motd.maven</groupId>??
- ????????????????<artifactId>os-maven-plugin</artifactId>??
- ????????????????<version>1.4.1.Final</version>??
- ????????????</extension>??
- ????????</extensions>??
- ????????<plugins>??
- ??
- ????????????<!--?protobuf?-->??
- ????????????<plugin>??
- ????????????????<groupId>org.xolstice.maven.plugins</groupId>??
- ????????????????<artifactId>protobuf-maven-plugin</artifactId>??
- ????????????????<version>0.5.0</version>??
- ????????????????<configuration>??
- ????????????????????<protocArtifact>com.google.protobuf:protoc:3.0.0-beta-2:exe:${os.detected.classifier}</protocArtifact>??
- ????????????????????<pluginId>grpc-java</pluginId>??
- ????????????????????<pluginArtifact>io.grpc:protoc-gen-grpc-java:0.14.0:exe:${os.detected.classifier}</pluginArtifact>??
- ????????????????????<protoSourceRoot>src/main/resources/proto</protoSourceRoot>??
- ????????????????</configuration>??
- ????????????????<executions>??
- ????????????????????<execution>??
- ????????????????????????<goals>??
- ????????????????????????????<goal>compile</goal>??
- ????????????????????????????<goal>compile-custom</goal>??
- ????????????????????????</goals>??
- ????????????????????</execution>??
- ????????????????</executions>??
- ????????????</plugin>??
- ??
- ????????</plugins>??
- ????</build>??
这样一来,在进行mvn compile时,会自动去src/main/resources/proto目录下查找proto文件,并在target目录里生成对应的.java、.class文件。
?
?
下面我们写一个服务端、一个客户端的helloworld程序,proto文件如下:
- syntax?=?"proto3";??
- ??
- package?grpc;??
- ??
- option?java_package?=?"com.zk_chs.grpc";??
- option?java_outer_classname?=?"HelloWorldServiceProto";??
- option?java_multiple_files?=?true;??
- ??
- service?HelloWorldService?{??
- ??rpc?SayHello?(HelloWorldRequest)?returns?(HelloWorldResponse)?{}??
- }??
- ??
- message?HelloWorldRequest?{??
- ??string?request?=?1;??
- }??
- ??
- message?HelloWorldResponse?{??
- ??string?response?=?1;??
- }??
当有option java_package存在时,会覆盖package属性,生成的文件如下:

?
?
?
接下来,需要先实现我们定义的HelloWorldService服务接口,该接口只需在服务端实现,客户端不用实现:
- public?class?HelloWorldRpcServiceImpl?implements?HelloWorldRpcServiceGrpc.HelloWorldRpcService?{??
- ??
- ????@Override??
- ????public?void?sayHello(HelloWorldRequest?request,?StreamObserver<HelloWorldResponse>?responseObserver)?{??
- ????????String?req?=?request.getRequest();??
- ????????HelloWorldResponse?resp?=?HelloWorldResponse.newBuilder()??
- ????????????????.setResponse("hello?"?+?req)??
- ????????????????.build();??
- ????????responseObserver.onNext(resp);??
- ????????responseObserver.onCompleted();??
- ????}??
- ??
- }??
?
服务端实现:
- public?class?GrpcServer?{??
- ??
- ????private?final?int?port?=?38628;??
- ??
- ????private?Server?server;??
- ??
- ????private?void?start()?throws?IOException?{??
- ????????server?=?ServerBuilder.forPort(port)??
- ????????????????.addService(HelloWorldRpcServiceGrpc.bindService(new?HelloWorldRpcServiceImpl()))???
- ????????????????.build()??
- ????????????????.start();??
- ????????Runtime.getRuntime().addShutdownHook(new?Thread()?{??
- ????????????@Override??
- ????????????public?void?run()?{??
- ????????????????GrpcServer.this.stop();??
- ????????????}??
- ????????});??
- ????}??
- ??
- ????private?void?stop()?{??
- ????????if?(server?!=?null)?{??
- ????????????server.shutdown();??
- ????????}??
- ????}??
- ??
- ????private?void?blockUntilShutdown()?throws?InterruptedException?{??
- ????????if?(server?!=?null)?{??
- ????????????server.awaitTermination();??
- ????????}??
- ????}??
- ??
- ????public?static?void?main(String[]?args)?throws?IOException,?InterruptedException?{??
- ????????final?GrpcServer?server?=?new?GrpcServer();??
- ????????server.start();??
- ????????server.blockUntilShutdown();??
- ????}??
- ??????
- }??
?
客户端实现:
- public?class?GrpcClient?{??
- ??
- ????private?final?ManagedChannel?channel;??
- ????private?final?HelloWorldRpcServiceGrpc.HelloWorldRpcServiceBlockingStub?blockingStub;??
- ??
- ????public?GrpcClient(String?host,?int?port)?{??
- ????????channel?=?ManagedChannelBuilder.forAddress(host,?port)??
- ????????????????.usePlaintext(true)??
- ????????????????.build();??
- ????????blockingStub?=?HelloWorldRpcServiceGrpc.newBlockingStub(channel);??
- ????}??
- ??
- ????public?void?shutdown()?throws?InterruptedException?{??
- ????????channel.shutdown().awaitTermination(5,?TimeUnit.SECONDS);??
- ????}??
- ??
- ????public?String?request(String?req)?{??
- ????????HelloWorldRequest?request?=?HelloWorldRequest.newBuilder()??
- ????????????????.setRequest(req)??
- ????????????????.build();??
- ????????return?blockingStub.sayHello(request).getResponse();??
- ????}??
- ??
- ????public?static?void?main(String[]?args)?throws?Exception?{??
- ????????GrpcClient?client?=?new?GrpcClient("localhost",?38628);??
- ????????String?req?=?"world!";??
- ????????String?response?=?client.request(req);??
- ????????System.out.println(response);??
- ????}??
- ??
- }??
?
?
然后进行测试,首先启动GrpcServer,再运行GrpcClient,在client的控制台能看到如下信息:

?
?
一个简易的grpc服务就完成了,当然,还有很多的不足:
1、例如异常信息处理(grpc有内置的异常信息)
2、连接每次都会断开,没有重复利用,效率低
?
下次的博客大概会介绍一下解决方法,比如采用commons-pool2连接池
?
Grpc应用,基本实现,http://zk-chs.iteye.com/blog/2308422
Grpc应用,搭配commons-pool2连接池实现连接复用,http://zk-chs.iteye.com/blog/2308730
Grpc应用,基本实现
原文:http://zk-chs.iteye.com/blog/2308422