使用grpc-server-spring-boot-starter及nacos搭建grpc服务

本文详细介绍了如何在Spring Cloud环境中利用Nacos配置管理和服务注册,结合protobuf-maven-plugin编译生成的protobuf库,实现provider和consumer之间的gRPC通信。通过创建cloud-grpc-provider和cloud-grpc-consumer模块,配置application.yml,以及使用GrpcService和@GrpcClient,展示了从服务注册到消费者调用的完整流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇文章《java使用protobuf-maven-plugin的插件编译proto文件》中,我们使用protobuf-maven-plugin已经生成了grpc的调用的库,这篇文章我们将讲解使用SpringCloud及nacos搭建grpc服务。

具体的实现步骤:

1. 先在github下载一个nacos的release版本应用,下载​​​​​​​地址。 解压缩之后,进到nacos目录,执行如下指令启动nacos,这里我们测试,所以启动的是单机服务:

sh ./bin/startup.sh -m standalone

运行成功后在网页访问:http://localhost:8848/nacos,打开后进到nacos登录页面,使用默认账号/密码:nacos/nacos进行登录。

登录成功后,我们可以看到nacos提供了ConfigManagement和ServiceManagement,我们要看的是服务注册中心的ServiceManagement。

2. 我们在上一章lib的工程中,创建三个module,分别为cloud-grpc-provider9090和cloud-grpc-provider9091和cloud-grpc-consumer10020。 前两个提供服务的grpc的provider的服务端, 后面一个consumer为grpc的消费端。项目结构如下:

3. 在父工程的POM文件中添加如下包依赖

 <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <jackson.version>2.11.1</jackson.version>
        <protobuf.plugin.version>0.6.1</protobuf.plugin.version>
        <spring.boot.version>2.3.9.RELEASE</spring.boot.version>
        <springcloud.version>Hoxton.SR9</springcloud.version>
        <springcloud.alibaba.version>2.1.0.RELEASE</springcloud.alibaba.version>
        <protobuf.version>3.14.0</protobuf.version>
        <grpc.java.version>1.35.0</grpc.java.version>
        <!--grpc.starter.version>2.11.0.RELEASE</grpc.starter.version-->
        <grpc.starter.version>2.13.1.RELEASE</grpc.starter.version>
    </properties>

    <dependencyManagement>
        <dependencies>
<!--            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${springcloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${springcloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- jackson-xml -->
            <dependency>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
                <version>${jackson.version}</version>
            </dependency>

            <!-- grpc -->
            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-client-spring-boot-starter</artifactId>
                <version>${grpc.starter.version}</version>
            </dependency>

            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-client-spring-boot-autoconfigure</artifactId>
                <version>${grpc.starter.version}</version>
            </dependency>

            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-server-spring-boot-starter</artifactId>
                <version>${grpc.starter.version}</version>
            </dependency>

            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-server-spring-boot-autoconfigure</artifactId>
                <version>${grpc.starter.version}</version>
            </dependency>


            <!-- proto -->
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-services</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-api</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-context</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>

            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-core</artifactId>
                <version>${grpc.java.version}</version>
            </dependency>
        </dependencies>

    </dependencyManagement>

这里我们使用的spring-boot版本与grpc-client-spring-boot-starter和grpc-server-spring-boot-starter使用的版本不同,所以后面我们需要在grpc的starter排除掉默认的spring-boot版本。同时grpc的相关一些库都使用统一的版本。

这里可以看到grpc底层使用的是netty实现的消息通讯

 4. 配置application.yml文件

//provider的application.yml

server:
  port: 8081

grpc:
  server:
    port: 9091
    security:
      enabled: false

spring:
  application:
    name: cloud-grpc-provider
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

# actuator management
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: '*'
//consumer的application.yml

server:
  port: 10020

spring:
  application:
    name: cloud-grpc-comsumber
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

grpc:
  client:
    cloud-grpc-provider:
      enableKeepAlive: true
      keepAliveWithoutCalls: true
      negotiationType: PLAINTEXT
    GLOBAL:
      security:
        client-auth-enabled: false

以上是provider和consumer的application.yml配置文件。 这里我们使用的同一台机器进行测试,所以要注意不同的provider和consumer应用的server的端口和grpc的端口不要相同。
同时在provider和consumer,将grpc的security的enable开关关掉。consumer端要注意的是设置negotiationType的类型为PLAINTEXT

5. provider和consumer引入相应的包

provider的maven引入:

<dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-server-spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>cn.ckeen</groupId>
            <artifactId>cloud-grpc-lib</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

consumer的maven引入:

 <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-client-spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>cn.ckeen</groupId>
            <artifactId>cloud-grpc-lib</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

两个包都引入了lib包,作为客户端和服务端通讯协议。使用nacos作为注册中心,实现负载均衡。

6. provider的service编写

@GrpcService
public class GreeterService extends SimpleGrpc.SimpleImplBase {

    private static Logger log = LoggerFactory.getLogger(GreeterService.class);

    // 引入该参数是为了做负载均衡验证
    @Value("${grpc.server.port}")
    private String serverPort;

    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
        String message = "server port:" + serverPort + ",Hello " + request.getName();
        final HelloReply.Builder replyBuilder = HelloReply.newBuilder().setMessage(message);
        responseObserver.onNext(replyBuilder.build());
        responseObserver.onCompleted();
        log.info("Returning " +message);

        responseObserver.onError(Status.INVALID_ARGUMENT.withDescription("测试出错").asException());
    }
}

首先使用GrpcService注解来标识服务,该服务继承自proto文件生成的grpc的SimpleGrpc.SimpleImplBase,同时实现了sayHello的方法,这里我们通过responseObserver将结果返回。

7. consumer的消费

consumer端比较简单,直接使用@GrpcClient的注解生成一个SimpleGrpc的Stub,然后进行调用即可

@Service
public class GreeterService {

    @GrpcClient("cloud-grpc-provider")
    private SimpleGrpc.SimpleBlockingStub simpleBlockingStub;

    public String greet(String name) {

        try {
            HelloReply response = simpleBlockingStub.sayHello(HelloRequest.newBuilder().setName(name).build());
            return response.getMessage();
        } catch (final StatusRuntimeException e) {
            return "FAILED with " + e.getStatus().getCode();
        }
    }

}

最终我们可以写一个controller来调用该服务进行测试,实现代码如下:

    @Resource
    private GreeterService greeterService;

    @GetMapping("greeter")
    public String greet(@RequestParam("name")String name){
        String result = greeterService.greet(name);
        return result;
    }

8. 测试验证

先启动两个provider,我们可以在nacos的service list看到两个provider的注册信息:

 启动consumer访问http://localhost:10020/greeter?name=keen可以看到有返回,刷新后端口还有变化

到此我们简单的一个grpc的服务就已经实现了

demo地址: https://github.com/keenw/spring-cloud-grpc-ck

### Nacos 配置中心在 Spring Boot 中启动时客户端未连接的问题解决方案 当在 Spring Boot 项目中使用 `nacos-config-spring-boot-starter` 并遇到 `Client not connected, current status:STARTING` 错误时,通常是由以下几个原因之一引起的: #### 1. **Nacos 客户端与服务器版本不兼容** 如果使用Nacos 客户端版本与 Nacos 服务端版本不一致,可能会导致此问题。建议检查并调整依赖项中的版本号以确保两者之间的兼容性[^1]。 修改 Maven 或 Gradle 文件中的依赖项如下所示: ```xml <!-- 排除默认的 nacos-client --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <exclusions> <exclusion> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </exclusion> </exclusions> </dependency> <!-- 手动指定 nacos-client 版本 --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.0.3</version> <!-- 根据实际需求选择合适的版本 --> </dependency> ``` #### 2. **gRPC 连接问题 (仅限于 Nacos 2.x 版本)** 在 Nacos 2.x 版本中,默认启用了 gRPC 协议用于内部通信。因此,在某些情况下可能需要额外开放特定端口来支持这些协议的工作[^4]。 - 确认防火墙设置是否允许访问以下端口号: - 主要管理界面和服务注册/发现端口:8848 - gRPC 数据传输所需端口:9848 和 9849 使用命令行工具验证当前系统的防火墙状态以及新增必要端口权限的操作方法可以参考下面的例子: ```bash # 列出所有已经开启的服务端口 firewall-cmd --list-ports # 增加新的 TCP 端口到永久规则里去 firewall-cmd --add-port=9848/tcp --permanent firewall-cmd --add-port=9849/tcp --permanent # 让更改立即生效 firewall-cmd --reload ``` #### 3. **Spring Cloud Alibaba 版本冲突** 不同版本间的组合也可能引发类似的异常情况。例如,较高版本的 Spring Boot 结合较低版本的 spring-cloud-alibaba 组件可能导致功能失效或运行失败等问题发生[^3]。 调整至稳定版次作为临时措施之一可有效缓解此类矛盾现象的存在风险;具体而言就是把 spring-cloud-alibaba 的版本降级为更早一些发布的稳定分支比如 `2.2.1.RELEASE`, `2.1.2.RELEASE` 或者其他经过广泛测试证明可靠的发行序列号即可满足基本应用场景下的正常使用需求而不会轻易再碰见上述提及过的那种状况再次重现出来影响正常业务流程运转效率等方面造成不良后果的发生几率大大减少了许多倍数以上程度范围之内都属于合理可控范畴以内水平线附近波动变化趋势较为平稳持续一段时间之后便能够逐渐趋于平衡状态恢复正常运作模式当中去了。 --- ### 示例代码片段 以下是针对上述分析的一个完整示例配置文件内容展示部分供参考学习之用: ```yaml spring: application: name: demo-service cloud: nacos: config: server-addr: localhost:8848 # 替换为您的 Nacos 实际地址 file-extension: yaml # 指定扩展名类型 ``` 同时记得更新项目的构建描述符文档(POM.XML),使其包含正确的库引用关系定义结构形式如下所列那样才行哦! ```xml <properties> <java.version>1.8</java.version> <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> ``` ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿CKeen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值