Bootstrap

Idea+maven+spring-cloud项目搭建系列--12 整合grpc

前言: grpc 是geogle 开源的rpc 通信框架,通过定义proto生成通信存根,像本地调用服务一样,进行远程服务的调用;

1 消费端服务提供

1.1 引入grpc 和 protobuf

<!-- RPC -->
<!-- RPC 服务调用 -->
<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-spring-boot-starter</artifactId>
    <version>2.10.1.RELEASE</version>
</dependency>
<!-- protobuf 协议缓冲区-->
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java-util</artifactId>
    <version>3.12.2</version>
</dependency>

1.2 要想根据proto文件生成服务的存根,这里引入对应的maven 插件:

<extensions>
	<!-- 确定当前的操作系统和体系结构 -->
    <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.6.2</version>
    </extension>
</extensions>
<plugin>
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.6.1</version>
    <configuration>
    	<!-- 消息体生成工具 -->
        <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
          <!-- java rpc 代码生成 -->
        <pluginId>grpc-java</pluginId>
        <!-- java rpc 代码生成功能 -->
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.32.1:exe:${os.detected.classifier}</pluginArtifact>
        <!-- proto 的文件源 -->
        <protoSourceRoot>src/main/proto</protoSourceRoot>
       <!-- <outputDirectory>src/main/java</outputDirectory>-->
       <!-- 消息体生成后不进行清除 -->
        <clearOutputDirectory>false</clearOutputDirectory>
    </configuration>
    <executions>
        <execution>
            <goals>
           		 <!-- 执行的任务 -->
                <goal>compile</goal>
                <goal>compile-custom</goal>
            </goals>
        </execution>
    </executions>
</plugin>

插件引入后如图所示:
在这里插入图片描述
插件安装完成会出现protobuf 插件:
在这里插入图片描述

1.3 定义proto 文件 hello.proto:

	// 语法使用proto3
    syntax = "proto3";


    //option java_multiple_files = false ;
    // java 生成的jar包类
    option java_package = "bl.grpc.es";
    // java 生成的消息类名称
    option java_outer_classname = "HelloWorldProto";

   // 该 proto 的包类名多个proto 文件package 不能相同
    package bl.es;
    // 请求参数
    message HelloRequest {
        string name = 1;
    }
    // 返回的结果
    message HelloResponse {
        string name = 1;
        string status = 2;
    }

    // rpc 服务
    service HelloService {
        // 定义hello 方法
        rpc hello(HelloRequest) returns(HelloResponse) {}
    }

通过maven ->compile 编译生成java 消息体及rpc 服务:
在这里插入图片描述
生成类所在路径为,改项目 target 目录下 \generated-sources\protobuf :
在这里插入图片描述
1.4 暴露要对外的接口 HelloServiceGrpcOne :

package org.lgx.bluegrass.bluegrasses.proto;

import bl.grpc.es.HelloServiceGrpc;
import bl.grpc.es.HelloWorldProto;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;

/**
 * @Description TODO
 * @Date 2023/2/28 11:21
 * @Author lgx
 * @Version 1.0
 */
// 服务端注解标识
@GrpcService
public class HelloServiceGrpcOne  extends  HelloServiceGrpc.HelloServiceImplBase{
    @Override
    public void hello(HelloWorldProto.HelloRequest request, StreamObserver<HelloWorldProto.HelloResponse> responseObserver) {
        // 数据处理并返回
        HelloWorldProto.HelloResponse reply = HelloWorldProto.HelloResponse.newBuilder()
                .setName("Hello ========== " + request.getName()).setStatus("200")
                .build();
        responseObserver.onNext(reply);
        responseObserver.onCompleted();
    }
}

bootstrap.yml 暴露grpc 服务端口:

grpc:
  server:
    port: 6000

至此服务端暴露完成;

2 消费端远程调用:

2.1 同服务端相同,也需要引入grpc 和 protobuf ;以及proto文件生成服务的存根,引入对应的maven 插件;
2.2 定义消费端:
1)HelloWorldClient :

package org.lgx.bluegrass.bluegrasscoree.proto;

import bl.grpc.es.HelloServiceGrpc;
import bl.grpc.es.HelloWorldProto;
import io.grpc.Channel;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;

/**
 * @Description TODO
 * @Date 2023/2/28 13:47
 * @Author lgx
 * @Version 1.0
 */
@Service
public class HelloWorldClient {

    @GrpcClient("cloud-grpc-server")
    private Channel serverChannel;

    public String hello(String name) {
        HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub(serverChannel);
        HelloWorldProto.HelloRequest.Builder builder = HelloWorldProto.HelloRequest.newBuilder().
                setName(name);
        HelloWorldProto.HelloResponse response = stub.hello(builder.build());
        return "{'responseStatus':'" + response.getStatus() + "','result':[]}"+response.getName();

    }
}

2)GrpcTestController :

package org.lgx.bluegrass.bluegrasscoree.controller.protogrpc;

import lombok.extern.slf4j.Slf4j;
import org.lgx.bluegrass.bluegrasscoree.proto.HelloWorldClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description TODO
 * @Date 2023/2/28 13:55
 * @Author lgx
 * @Version 1.0
 */
@Slf4j
@RestController
public class GrpcTestController {
    @Autowired
    private HelloWorldClient service;

    @GetMapping(value = "/hello")
    public String test(String name) {
        String result = "";
        try {
            result = service.hello(name);
            log.info("respString : {}", result);
            return result;
        } catch (Throwable e) {
            log.error("hello error", e);
        }
        return result;
    }
}

1.3 消费端bootstrap.yml定义要连接的服务端:

grpc:
  client:
  	# 服务名称
    cloud-grpc-server:
    	# 服务地址
      address: static://localhost:6000  #指定grpc服务端地址
      # 保持长连接
      enableKeepAlive: true
      keepAliveWithoutCalls: true
      negotiationType: plaintext

1.4 测试:
http://localhost:9082/hello?name=%E5%BC%A0%E4%B8%8912344
在这里插入图片描述

总结:
1 ) 需要引入proto ,java生成插件生成消息体和rpc 的服务调用代码;
2 ) 服务端通过继承rpc 类实现具体业务的实现;
3 ) 消费端通过注入rpc 的bean 完成远程方法的调用;
4)grpc 使用协议存根来替代dubbo 中定义的要外发布的接口,更加的灵活;

参考:
1 grpc 介绍;
2 grpc 协议缓冲区;

;