grpc
一、开始使用
- 根据gRPC-Java编译框架的地址我们可以看到具体的操作流程,当然,刚开始第一步时引入grpc的maven依赖
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.36.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.36.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.36.0</version>
</dependency>
<dependency> <!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
- 下面引入编译插件,引入插件编译的时候,注意下,proto存放位置与该包放在同位置下,它默认会根据proto中设置的package去找,我的proto文件的package是设置的
package proto
,当然如果要放在其他位置,这个package是需要变化的,不然插件会找不到
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
- 完整的
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ProtocolBuffer</groupId>
<artifactId>ProtocolBuffer</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.36.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.36.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.36.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.36.0</version>
</dependency>
<dependency> <!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
- 搭建完成后,开始进行简单的demo测试
- 创建一个proto文件
grpcDemo.proto
syntax = "proto3";
package proto;
option java_package = "com.protocol.grpcdemo";
option java_outer_classname = "GrpcDemo";
message req{
string msg = 1;
}
message res{
string resMsg = 1;
}
//这是服务,会自动生成服务器端的Service与客户端的调用的Stub。也就是说,我们在
service sayHelloRpc{
rpc sayHello(req) returns (res){};
}
- 点击install生成代码
- 将上面两个类复制到src中的对应目录下,就可以开始写服务器端和客户端了。
- 服务器代码
TestDemo.java
package com.protocol.grpcdemo;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import org.junit.Test;
import java.io.IOException;
/**
* @author chengfei.liu
* @since 2021/2/28 11:06
*/
public class TestDemo {
private Server server;
public void test() throws IOException, InterruptedException {
int port = 10086;
System.out.println("服务器启动了");
//初始化服务器,绑定端口,并添加服务,服务是接口,需要自己实现里面的逻辑
server = ServerBuilder.forPort(port).addService(new sayHelloRpcGrpc.sayHelloRpcImplBase() {
@Override
public void sayHello(GrpcDemo.req request, StreamObserver<GrpcDemo.res> responseObserver) {
//主要业务逻辑
System.out.println(request.getMsg());
//创建需要返回的参数实体
GrpcDemo.res.Builder builder = GrpcDemo.res.newBuilder();
builder.setResMsg("这是服务器相应的信息");
GrpcDemo.res build = builder.build();
//发送
responseObserver.onNext(build);
//关闭连接
responseObserver.onCompleted();
}
}).build().start();
// server.awaitTermination();
//关闭服务器
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
super.run();
System.out.println("服务器即将关闭");
TestDemo.this.stop();
System.out.println("服务器已关闭");
}
});
}
private void stop(){
if(server!=null){
server.shutdownNow();
}
}
//设置堵塞态,一直再等待客户端的连接
private void blockUtilShutDown() throws InterruptedException {
if(server!=null){
server.awaitTermination();
}
}
public static void main(String[] args) throws Exception {
TestDemo testDemo = new TestDemo();
testDemo.test();
testDemo.blockUtilShutDown();
}
}
- 客户端代码
package com.protocol.grpcdemo;
import io.grpc.CallOptions;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.TimeUnit;
/**
* @author chengfei.liu
* @since 2021/2/28 11:31
*/
public class TestDemoClient {
//添加通道,用于连接客户端与服务器,方便传输,可以了解一下NIO
private ManagedChannel channel;
//这是主要客户端工具,里面封装了客户端可以调用的方法、设置选项等等
private sayHelloRpcGrpc.sayHelloRpcBlockingStub blockingStub;
//创建客户端
public void sayHelloClient(String address,int port){
//利用ManagedChannelBuilder初始化一个通道,进行连接到服务器,注意:如果需要使用字符串传输,需要添加usePlaintext,否则会出现异常HTTP/2 client preface string missing or corrupt. Hex dump for received bytes: 504f5354202f68656
channel = ManagedChannelBuilder.forAddress(address,port).usePlaintext().build();
//初始化sayHelloRpcGrpc的客户端工具,并将通道添加到其中
blockingStub = sayHelloRpcGrpc.newBlockingStub(channel);
}
//延迟关闭
public void shudown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
//RPC调用
public void query(String msg){
//创建调用参数实体
GrpcDemo.req build = GrpcDemo.req.newBuilder().setMsg(msg).build();
//调用远程接口并得到返回值
GrpcDemo.res res = blockingStub.sayHello(build);
System.out.println(res.getResMsg());
}
public static void main(String[] args) {
TestDemoClient testDemoClient = null;
try {
testDemoClient = new TestDemoClient();
testDemoClient.sayHelloClient("127.0.0.1", 10086);
testDemoClient.query("这是客户端发来的信息");
}catch (Exception e) {
assert testDemoClient!=null;
try {
testDemoClient.shudown();
}catch (InterruptedException ex){
ex.printStackTrace();
}
}
}
}
- 结果