Springboot整合gRPC实践

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

基本的整合就这样,具体实现的还需要根据具体业务去做一些实现,还有就是一些其他的参数配置,可以根据官网文档,做一些相应的配置。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值