手把手带你写一个SpringBoot + gRPC服务

请注意,本文不会对gRPC基础概念进行解释,而是着重介绍服务的搭建过程。如果你是零基础的伙伴,请先自行学习gRPC的基础知识。接下来,让我们在本地环境下搭建gRPC客户端和服务端,并成功建立通讯发送消息的方式,来学习gRPC在Spring Boot项目中的应用。

客户端(发送rpc请求)

1、导入maven依赖

包含rpc所使用的依赖和构建protobuf的插件。完整的<dependencies><build>如下:

xml 复制代码
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty-shaded</artifactId>
    <version>1.59.1</version>
    <scope>runtime</scope>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.59.1</version>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.59.1</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>
</dependencies>

<build>
  <extensions>
    <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.7.1</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.24.0:exe:${os.detected.classifier}</protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.59.1:exe:${os.detected.classifier}</pluginArtifact>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>
            <goal>compile-custom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

导入成功后,可以在maven的插件中看到protobuf选项;

2、编写Proto文件

在main目录下创建proto软件包,将编写好的Proto文件放在该目录(src/main/proto)下。示例Proto文件内容如下

protobuf 复制代码
syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.example.server";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package com.example.server;


service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

完成Proto文件编写后,执行mvn install命令。你会在target/generated-sources/protobuf路径下看到gRPC编译生成的Java代码。这些生成的代码是实现gRPC在不同语言间进行RPC通讯的基础。

3、编写客户端代码

创建一个HelloWorldClient类,实例化stub对象,并发送rpc请求的方法;

java 复制代码
@Service
public class HelloWorldClient {

    private GreeterGrpc.GreeterBlockingStub stub;

    @Value("${grpc.hello-world.host}")
    private String host;
    @Value("${grpc.hello-world.port}")
    private Integer port;

    @PostConstruct
    void init() {
        ManagedChannel channel =
        ManagedChannelBuilder.forAddress(host, port)
        .keepAliveWithoutCalls(true)
        .keepAliveTime(60, TimeUnit.SECONDS)
        .keepAliveTimeout(3, TimeUnit.SECONDS)
        .idleTimeout(60, TimeUnit.SECONDS)
        .maxInboundMessageSize(Integer.MAX_VALUE)
        .usePlaintext().build();
        stub = GreeterGrpc.newBlockingStub(channel);
    }

    /**
     * 说"你好"
     *
     * @param name 名字
     * @return {@link String}
     */
    public String sayHello(String name) {

        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply helloReply = stub.sayHello(request);
        return helloReply.getMessage();
    }
}

这里我配置的gRPC服务端地址如下,请根据实际情况修改host和port的值。

yaml 复制代码
grpc:
  hello-world:
    host: 127.0.0.1
    port: 6565

接下来,让我们继续开发服务端的代码。

服务端(处理rpc请求并返回处理数据)

1、导入maven依赖

与客户端依赖略有不同,服务端中我们使用了grpc-spring-boot-starter

xml 复制代码
<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.53.0</version>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.53.0</version>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  </dependency>
  <dependency>
    <groupId>org.lognet</groupId>
    <artifactId>grpc-spring-boot-starter</artifactId>
    <version>2.3.2</version>
  </dependency>


</dependencies>

<!-- 添加protobuf-maven-plugin插件 编译proto文件-->
<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.17.3:exe:${os.detected.classifier}</protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.0:exe:${os.detected.classifier}</pluginArtifact>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>
            <goal>compile-custom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
</project>

2、导入Proto文件

这里的proto文件尽量和客户端的保持一致,完成和客户端步骤2同样的事儿。需要注意的是,在proto文件中,用package声明生成的Java类的包名,请与服务端实现类的包结构保持一致,这样才能正常地完成依赖导入和方法重写;

例如:

3、编写服务端实现类代码

  1. @GRpcService:用于标记这个类是一个gRPC服务端的实现类。它告诉Spring Boot框架将这个类注册为一个gRPC服务端,并自动处理gRPC请求。
  2. 继承自GreeterGrpc.GreeterImplBase类,表示它是rpc服务Greeter的实现类,在类中,我们可以重写rpc接口的实现方法,来处理接收到请求;
java 复制代码
/**
 * hello service impl
 *
 * @author yangyang
 * @date 2023/11/30
 */
@GRpcService
@Slf4j
public class HelloServiceImpl extends GreeterGrpc.GreeterImplBase {


    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
        // 获取客户端发送的请求消息
        String name = request.getName();
        // 构建响应消息
        HelloReply response = HelloReply.newBuilder()
        .setMessage("Hello, " + name + "!")
        .build();
        log.info("[grpc server]: response: {}", response);

        // 发送响应消息
        responseObserver.onNext(response);
        // 通知客户端响应已经完成
        responseObserver.onCompleted();
    }
}

4、配置端口号,启动服务

可通过此配置修改rpc的端口号(默认6565)

yaml 复制代码
grpc:
  # grpc server port
  port: 6565
server:
  port: 8081

服务启动后,可以在日志中看到端口信息

可以选择使用通过客户端发送请求来测试服务,或者使用postman等工具发送rpc接口。至此,一个简单且完整的SpringBoot gRPC客户端与服务端开发完成!

酸奶小肥阳原创,欢迎阅读点赞加收藏,关注我随时与我技术交流吧😄

相关推荐
王码码20359 小时前
Go语言的测试:从单元测试到集成测试
后端·golang·go·接口
王码码20359 小时前
Go语言中的测试:从单元测试到集成测试
后端·golang·go·接口
嵌入式×边缘AI:打怪升级日志10 小时前
使用JsonRPC实现前后台
前端·后端
小码哥_常10 小时前
从0到1:Spring Boot 中WebSocket实战揭秘,开启实时通信新时代
后端
lolo大魔王11 小时前
Go语言的异常处理
开发语言·后端·golang
IT_陈寒13 小时前
Python多进程共享变量那个坑,我差点没爬出来
前端·人工智能·后端
码事漫谈13 小时前
2026软考高级·系统架构设计师备考指南
后端
AI茶水间管理员14 小时前
如何让LLM稳定输出 JSON 格式结果?
前端·人工智能·后端
其实是白羊14 小时前
我用 Vibe Coding 搓了一个 IDEA 插件,复制URI 再也不用手动拼了
后端·intellij idea
用户83562907805115 小时前
Python 操作 Word 文档节与页面设置
后端·python