gRPC是由google推出的高性能的RPC框架,基于http2和protobuf,下面使用如下java示例带大家初步认识gRPC。
一、引入依赖
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.21.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.21.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.21.0</version>
</dependency>
</dependencies>
二、添加插件
添加的插件作用是将.proto
文件编译为java代码。
插件配置中goals
中compile表示编译.proto
文件为Message对象,compile-custom表示编译.proto
文件为gRPC对象。
注意:此插件编译后输出的java代码不在源码目录下,默认位置在打包目录的generated-sources/protobuf/文件夹下,可参考插件官方文档
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.5.0.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.1</version>
<configuration>
<protocArtifact>
com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>
io.grpc:protoc-gen-grpc-java:1.21.0:exe:${os.detected.classifier}
</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
若需要将Message源文件和gRPC源文件输出到不同的目录,则可以在maven的配置文件下添加如下配置:
<properties>
<!-- Message源文件输出目录 -->
<javaOutputDirectory>${project.basedir}/src/main/java-proto</javaOutputDirectory>
<!-- gRPC源文件输出目录 -->
<protocPluginOutputDirectory>
${project.basedir}/src/main/java-grpc
</protocPluginOutputDirectory>
</properties>
三、编写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<HelloResp> 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();
}
}