之前用GRPC主要是用Golang,Java之前基本只停留在会写hello world阶段。现在工作上需要用到Java的GRPC,所以不得不从头开始。让我沮丧的是,网上现有的教程基本都跑不通,然后Github上的grpc-java库按照readme一步一步走又提示一个网站不可达(不知道是不是被墙了)。靠着摸索一步一步地把一个Java的GRPC基本的HelloWorld弄通了。我主要参考的是这篇博客:
https://blog.csdn.net/qq_35047503/article/details/80985794
写GRPC程序其实总结起来就是:利用protobuf将定义的消息和服务生成对应语言的源代码,然后下载对应语言的grpc库,通过grpc库调用生成的服务,传递消息。
我的环境是ubuntu 16.04,之前我的电脑上是装了protoc命令的,GRPC程序需要使用protoc将.proto文件生成对应的源代码文件。没有装的话百度一下也会有很多教程。
定义proto文件helloworld.proto:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "demo";
option java_outer_classname = "HelloWorldProto";
//option java_generic_services = true;
// 可以生成rpc接口
package helloworld;
service GreetHelloWorld {
rpc SayHello (HelloWorldRequest) returns (HelloWorldResponse);
}
message HelloWorldRequest {
string name = 1;
}
message HelloWorldResponse {
string message = 1;
}
用这个来生成java源文件。有一些教程上面说把这个文件放到一个maven工程中可以一键自动生成java文件,但是我试了没有成功。如果您看到这篇文章知道如何利用maven生成java源文件的话希望您能告诉我一下。
此时还不够,需要下载protoc的java插件,否则只会针对message生成java文件,我们定义的service GreetHelloWorld没有办法生成java文件。需要下载protoc-gen-grpc-java插件,下载地址:https://repo1.maven.org/maven2/io/grpc/protoc-gen-grpc-java/
文件名里就是具体用于哪个平台的grpc-java插件,虽然都是.exe结尾,但是不都是windows平台下面的东西。将grpc-java插件可执行文件下载下来即可。
编译proto文件:
protoc --java_out=./ ./helloworld.proto
这条命令会将定义的message编译成.java文件
protoc --plugin=protoc-gen-grpc-java=grpc-java插件可执行文件路径 --grpc-java_out=./ ./helloworld.proto
这条命令将定义的service编译成.java文件。当前目录下会生成demo目录,目录下包含以下java源文件:GreetHelloWorldGrpc.java,HelloWorldProto.java,HelloWorldRequest.java,HelloWorldRequestOrBuilder.java,HelloWorldResponse.java,HelloWorldResponseOrBuilder.java。
GRPC程序编写采用mevan,下载地址:http://maven.apache.org/download.cgi
解压以后,将mevan目录下的bin目录加入到PATH环境变量中:
sudo gedit /etc/profile
在文件末尾加上一句:
export PATH=$PATH:mevan路径/bin
打开eclipse,建立一个mevan项目,eclipse目前的版本都是自带mevan项目的。groudId设为com.mingluck.kang,artifactId设为gPRC-RPC。在src/main/java下建立一个java包demo,将protoc生成的java源文件放到这个目录下,在这个目录下建立HelloWorldServer.java文件,输入grpc服务器程序:
package demo;
import io.grpc.Server;
import java.io.IOException;
import demo.GreetHelloWorldGrpc.GreetHelloWorldImplBase;
import io.grpc.ServerBuilder;
import io.grpc.BindableService;
import io.grpc.stub.StreamObserver;
public class HelloWorldServer {
private int port = 8851;
private Server server;
private void start() throws IOException {
server = ServerBuilder.forPort(port)
.addService((BindableService) new GreeterHelloWorldImpl())
.build()
.start();
System.out.println("service start...");
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
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();
}
}
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("new server");
final HelloWorldServer server = new HelloWorldServer();
server.start();
server.blockUntilShutdown();
}
// 实现 定义一个实现服务接口的类
private class GreeterHelloWorldImpl extends GreetHelloWorldImplBase {
public void sayHello(HelloWorldRequest req, StreamObserver responseObserver) {
// 具体其他丰富的业务实现代码
System.err.println("service:" + req.getName());
HelloWorldResponse reply = HelloWorldResponse.newBuilder().setMessage(("Hello: " + req.getName())).build();
responseObserver.onNext(reply); responseObserver.onCompleted();
}
}
}
更改pom.xml文件内容为:
4.0.0
com.mingluck.kang
gPRC-RPC
0.0.1-SNAPSHOT
jar
gPRC-RPC
http://maven.apache.org
UTF-8
junit
junit
3.8.1
test
io.grpc
grpc-netty
1.10.0
io.grpc
grpc-protobuf
1.10.0
io.grpc
grpc-stub
1.10.0
kr.motd.maven
os-maven-plugin
1.4.1.Final
org.xolstice.maven.plugins
protobuf-maven-plugin
0.5.0
com.google.protobuf:protoc:3.6.0:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:1.10.0:exe:${os.detected.classifier}
compile
compile-custom
进入pom.xml文件所在目录,运行命令:
mvn compile
此时grpc所依赖的库会下载到本机并且导入到当前项目中。我进行到这一步的时候出现了编译错误,就是子类里某些方法有@java.lang.override标签但是父类中并没有该方法,将override标签注释掉即可。
运行服务器程序,grpc java服务器程序启动起来。
grpc java客户端程序同样道理的搭建。客户端代码:
package com.mingluck.kang.gPRC_RPC;
import java.util.concurrent.TimeUnit;
import demo.GreetHelloWorldGrpc;
import demo.GreetHelloWorldGrpc.GreetHelloWorldBlockingStub;
import demo.HelloWorldRequest;
import demo.HelloWorldResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class HelloWorldClient {
private final ManagedChannel channel;
private final GreetHelloWorldBlockingStub blockingStub;
public HelloWorldClient(String host,int port){
channel = ManagedChannelBuilder.forAddress(host,port)
.usePlaintext(true)
.build();
blockingStub = GreetHelloWorldGrpc.newBlockingStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
public void greet(String name){
HelloWorldRequest request = HelloWorldRequest.newBuilder()
.setName(name)
.build();
HelloWorldResponse response = blockingStub.sayHello(request);
System.out.println(response.getMessage());
}
public static void main(String[] args) throws InterruptedException {
HelloWorldClient client = new HelloWorldClient("127.0.0.1", 8851);
for(int i=0;i<5;i++){
client.greet("world:"+i);
}
}
}