SpringBoot 整合 gRPC

本贴最后更新于 543 天前,其中的信息可能已经时过境迁

简介

  gRPC 是 google 开源的一个高性能、跨语言的 RPC 框架,基于 HTTP2 协议,基于 protobuf 3.x,基于 Netty 4.x +。

对于开发者而言:

1)需要使用 protobuf 定义接口,即.proto 文件。

2)然后使用 compile 工具生成特定语言的执行代码,比如 JAVA、C/C++、Python 等。类似于 thrift,为了解决跨语言问题。

3)启动一个 Server 端,server 端通过侦听指定的 port,来等待 Client 链接请求,通常使用 Netty 来构建,GRPC 内置了 Netty 的支持。

4)启动一个或者多个 Client 端,Client 也是基于 Netty,Client 通过与 Server 建立 TCP 常链接,并发送请求;Request 与 Response 均被封装成 HTTP2 的 stream Frame,通过 Netty Channel 进行交互。

proto3

编写 proto3 文件

文件命名为 pb.proto。

syntax = "proto3";

option java_multiple_files = true;
option java_package = "org.example.entity";
option java_outer_classname = "UserServiceProto";

service UserService {
  // 注册接口
  rpc register(RegisterReq) returns (RegisterRsp);
}

message RegisterReq {
  // 手机号
  string Phone = 1;
  // 用户ID
  string UserId = 2;
}

message RegisterRsp {
  // 业务状态码
  int32 code = 1;
  // 信息
  string msg = 2;
}

根据 proto 生成代码

  1. 创建一个空的项目。

    image.png

  2. pom 文件内容如下。

    <?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>org.example</groupId>
        <artifactId>proto</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <jackson.version>2.8.3</jackson.version>
            <grpc.version>1.6.1</grpc.version>
            <os.plugin.version>1.5.0.Final</os.plugin.version>
            <protobuf.plugin.version>0.5.0</protobuf.plugin.version>
            <protoc.version>3.3.0</protoc.version>
            <grpc.netty.version>4.1.14.Final</grpc.netty.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty</artifactId>
                <version>${grpc.version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
                <version>${grpc.version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
                <version>${grpc.version}</version>
            </dependency>
            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-common</artifactId>
                <version>${grpc.netty.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-annotations</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
                <version>${jackson.version}</version>
            </dependency>
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson.version}</version>
            </dependency>
        </dependencies>
    
        <build>
            <extensions>
                <extension>
                    <groupId>kr.motd.maven</groupId>
                    <artifactId>os-maven-plugin</artifactId>
                    <version>${os.plugin.version}</version>
                </extension>
            </extensions>
            <plugins>
                <plugin>
                    <groupId>org.xolstice.maven.plugins</groupId>
                    <artifactId>protobuf-maven-plugin</artifactId>
                    <version>${protobuf.plugin.version}</version>
                    <configuration>
                        <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
                        <pluginId>grpc-java</pluginId>
                        <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    
  3. java 同级目录下添加 proto 目录,将编写好的 proto 文件放到该目录下。

    image.png

  4. 依次执行 mvn 命令 protobuf:compile 和 protobuf:compile-custom 编译生成 java 文件。

    image.png

  5. 生成后的文件存放在 target 目录下。

    image.png

    可以对比看出,生成的 java 文件和 proto 文件中定义的 service 和 message 是对应的。其中 option java_multiple_files = true; 配置决定是将 message 定义为一个文件还是内部类,将配置修改为 false 后再次执行 mvn 命令后会发现生成的文件变成以下这种,这就是把 message 定义为了内部类。不过这两种对功能上并无影响,开发者可以自行选择。

    image.png

    推荐将生成代码的项目单独存放,不要合并到开发项目中。因为 pom 中引入的 jar 和插件只是为了生成代码,后续在 SpringBoot 中使用 gRPC 并不需要这些 jar。示例项目放到了 96XL/proto: proto 文件生成 (github.com),需要的可以自取。

SpringBoot 整合

生成代码的项目、服务端项目、客户端项目三者可以完全分离,单独使用哪个项目都可以。例如使用服务端给外部系统提供 gRPC 接口,或者使用客户端调用外部系统的 gRPC 接口。

服务端

  1. 添加 maven 依赖。

    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-server-spring-boot-starter</artifactId>
        <version>2.13.1.RELEASE</version>
    </dependency>
    
  2. 服务端代码(记得将生成的类加到项目中)。

    @Slf4j
    @GrpcService
    public class UserGrpcServer extends UserServiceGrpc.UserServiceImplBase {
    
        public void register(UserServiceProto.RegisterReq request, StreamObserver<UserServiceProto.RegisterRsp> responseObserver) {
            // 接收到的参数
            log.info(request.toString());
            // 响应
            UserServiceProto.RegisterRsp reply = UserServiceProto.RegisterRsp.newBuilder().setCode(0).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
    
  3. 配置文件添加配置。

    grpc:
      server:
        port: 7777
    

客户端

  1. 添加 maven 依赖。
    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-client-spring-boot-starter</artifactId>
        <version>2.13.1.RELEASE</version>
    </dependency>
    
  2. 客户端代码(记得将生成的类加到项目中)。
    @Service
    public class UserGrpcClient {
    
        @GrpcClient("userServiceGrpc")
        private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;
    
        public void register(String phone, String userId) {
            UserServiceProto.RegisterReq registerReq = UserServiceProto.RegisterReq.newBuilder().setPhone(phone).setUserId(userId).build();
            userServiceBlockingStub.register(registerReq);
        }
    }
    
  3. 配置文件添加配置。这里的 IP 就是服务端的 IP,端口号要和服务端指定的端口号保持一致。userServiceGrpc 就是客户端代码 @GrpcClient("userServiceGrpc") 中指定的值,两者保持一致即可,和服务端没有关系。
    grpc:
      client:
        userServiceGrpc:
          address: static://localhost:7777
          negotiationType: PLAINTEXT
    
  4. 接口中正常调用方法即可。
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    940 引用 • 1458 回帖 • 156 关注
  • gRpc
    10 引用 • 8 回帖 • 52 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...