Springboot整合gRPC
最近公司其他服务为go语言开发,这边Java服务需要进行交互,考虑到效率和系统发展的问题,因此使用了gRPC来作为rpc框架。由于基本是第一次使用Springboot集成gRPc,经过一系列的踩坑,终于完成了项目的开发,这边记录下整合方式。
gRPC简介
gRPC是谷歌开源的基于go语言的一个现代的开源高性能RPC框架,可以在任何环境中运行。它可以有效地连接数据中心内和跨数据中心的服务,并提供可插拔的支持,以实现负载平衡,跟踪,健康检查和身份验证。它还适用于分布式计算的最后一英里,用于将设备,移动应用程序和浏览器连接到后端服务。
proto3
Protocol Buffers是一个跨语言、跨平台的具有可扩展机制的序列化数据工具。也就是说,我在ubuntu下用python语言序列化一个对象,并使用http协议传输到使用java语言的android客户端,java使用对用的代码工具进行反序列化,也可以得到对应的对象。可以根据客户端与服务端约定同一个Proto文件进行交互,然后双方可以根据proto文件反序列化为相应语言的对象进行交互。只是这个对象可能是自动生成的,会有点点不适应。
springboot整合
Grpc Spring Boot Starter地址:https://github.com/yidongnan/grpc-spring-boot-starter
相关依赖
<properties>
<java.version>1.8</java.version>
<grpc.version>1.6.1</grpc.version>
<protobuf.version>3.3.0</protobuf.version>
</properties>
<!-- google.protobuf -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-common-protos</artifactId>
<version>1.12.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.17.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.6-jre</version>
</dependency>
proto文件生成依赖
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
</pluginArtifact>
<!--默认值-->
<protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
proto文件
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.aiccms.device.grpc.lib";
option java_outer_classname = "DeviceFixProto";
option objc_class_prefix = "HLW";
package device;
// The device service definition.
service DeviceFixService {
// Sends a message
rpc insertDeviceFix (deviceFix) returns (booleanReply){}
rpc updateDeviceFix (deviceFix) returns (booleanReply){}
rpc searchDeviceFix (conditionsRequest) returns (deviceFix){}
rpc deleteDeviceFix (conditionsRequest) returns (booleanReply){}
}
// The request message .
message conditionsRequest {
string id = 1;
}
message deviceFix {
string id=1;
string serialNum=2;
string userNum=3;
int32 status=4;
int32 type=5;
string address=6;
string createtime=7;
string updatetime=8;
}
// The response message
message booleanReply {
bool reply = 1;
}
// The response message
message objectReply {
bool reply = 1;
}
java对象生成
使用mvn命令 protobuf:compile 和protobuf:compile-custom命令编译生成java文件
将会根据proto文件生成对应的Java对象。
grpc服务端编写
@Slf4j
@GrpcService()
public class DeviceGrpcService extends DeviceFixServiceGrpc.DeviceFixServiceImplBase {
@Override
public void insertDeviceFix(deviceFix request, StreamObserver<booleanReply> responseObserver) {
// 返回体构建,入参在request中,这边省略业务代码
booleanReply reply = booleanReply.newBuilder().build();
// 返回参数
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
继承生成对象,具体实现其中定义好的方法,即双方在文件中约定好的参数以及接口。
定义grpc服务端接口。
grpc:
server:
port: 9090
grpc客户端编写
public class DeviceGrpcClient {
/**
* 阻塞模式
* 拦截器需要在注解里写明
*/
@GrpcClient(value = "myservice", interceptors = HeaderClientInterceptor.class)
DeviceFixServiceGrpc.DeviceFixServiceBlockingStub deviceFixServiceBlockingStub;
/**
* 其中定义好的一个接口
*
* @param request
* @return
*/
public booleanReply insertDeviceFix(deviceFix request) {
// 业务代码
return deviceFixServiceBlockingStub.insertDeviceFix(request);
}
}
客户端可以实现自定义拦截器,在数据抵达channel之前对数据拦截做一些相关操作,服务端也可以实现相应拦截器,双方做一些数据的交互。
@GrpcGlobalClientInterceptor
@Slf4j
public class HeaderClientInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
// 这边可以将自己需要的请求头传入,双方做好约定校验
super.start(
new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(
responseListener) {
@Override
public void onHeaders(Metadata headers) {
super.onHeaders(headers);
}
}, headers);
}
};
}
}
配置文件
client:
myservice:
# 传输类型,默认是ssl
negotiationType: PLAINTEXT
address: static://127.0.0.1:5012
基本的整合就这样,具体实现的还需要根据具体业务去做一些实现,还有就是一些其他的参数配置,可以根据官网文档,做一些相应的配置。