gRPC是由google推出的高性能的RPC框架,基于http2和protobuf,下面使用如下java示例带大家初步认识gRPC。
一、引入依赖
io.grpc
grpc-netty-shaded
1.21.0
io.grpc
grpc-protobuf
1.21.0
io.grpc
grpc-stub
1.21.0
二、添加插件
添加的插件作用是将.proto文件编译为java代码。
插件配置中goals中compile表示编译.proto文件为Message对象,compile-custom表示编译.proto文件为gRPC对象。
注意:此插件编译后输出的java代码不在源码目录下,默认位置在打包目录的generated-sources/protobuf/文件夹下,可参考插件官方文档
kr.motd.maven
os-maven-plugin
1.5.0.Final
org.xolstice.maven.plugins
protobuf-maven-plugin
0.5.1
com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:1.21.0:exe:${os.detected.classifier}
compile
compile-custom
若需要将Message源文件和gRPC源文件输出到不同的目录,则可以在maven的配置文件下添加如下配置:
${project.basedir}/src/main/java-proto
${project.basedir}/src/main/java-grpc
三、编写protobuf文件
我们这里书写一个简单的hello_world.proto文件,放在src/main/proto文件夹下(插件寻找proto文件的默认目录)
syntax = "proto3";
option java_package = "com.example.grpc";
option java_multiple_files = true;
option java_outer_classname = "HelloWorldProto";
message Greeting {
string name = 1;
}
message HelloResp {
string reply = 1;
}
service HelloWorld {
rpc sayHello (Greeting) returns (HelloResp);
}
说明:
java_package表示生成java代码的包名;
java_multiple_files = true 表示生成多个java文件,若不设置该属性,则只会生成一个java文件;
java_outer_classname表示包含message描述的java文件的类名;
四、生成java代码
执行如下图所示protobuf:compile和protobuf:compile-custom两个指令:
将会生成如下的目录:
五、编写服务端代码
1. 实现服务端的sayHello方法
这里实现的是传入名字,然后返回Hello, {name}!
package com.example.grpc;
import io.grpc.stub.StreamObserver;
public class HelloWorldRpcService extends HelloWorldGrpc.HelloWorldImplBase {
@Override
public void sayHello(Greeting request, StreamObserver responseObserver) {
String name = request.getName();
HelloResp resp = HelloResp.newBuilder()
.setReply("Hello " + name + "!")
.build();
responseObserver.onNext(resp);
responseObserver.onCompleted();
}
}
2. 创建gRPC的服务端package com.example.grpc;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
public class GrpcServer {
private Server server;
/**
* @param port 服务端占用的端口
*/
public GrpcServer(int port) {
server = ServerBuilder.forPort(port)
// 将具体实现的服务添加到gRPC服务中
.addService(new HelloWorldRpcService())
.build();
}
public void start() throws IOException {
server.start();
}
public void shutdown() {
server.shutdown();
}
}
六、创建客户端
创建客户端调用Server端的服务
package com.example.grpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class HelloWorldClient {
private final HelloWorldGrpc.HelloWorldBlockingStub blockingStub;
/**
* @param host gRPC服务的主机名
* @param port gRPC服务的端口
*/
public HelloWorldClient(String host, int port) {
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(host, port)
// 使用非安全机制传输
.usePlaintext()
.build();
blockingStub = HelloWorldGrpc.newBlockingStub(managedChannel);
}
public String sayHello(String name) {
Greeting greeting = Greeting.newBuilder()
.setName(name)
.build();
HelloResp resp = blockingStub.sayHello(greeting);
return resp.getReply();
}
}
七、启动测试
编写主类,测试服务端和客户端。
运行如下代码,若无异常,将会输出 Hello, HanMeiMei!。
package com.example.grpc;
public class HelloWorldApp {
public static void main(String[] args) throws Exception {
int port = 8000;
GrpcServer server = new GrpcServer(port);
server.start();
HelloWorldClient client = new HelloWorldClient("localhost", port);
String reply = client.sayHello("HanMeiMei");
System.out.println(reply);
server.shutdown();
}
}