前言: 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 中定义的要外发布的接口,更加的灵活;