grpc 介绍与整合springboot
1.grpc介绍
1.1定义
grpc是谷歌的一种高性能、开源的通用型RPC框架;支持多达十几种常用语言,它的原理是通过 IDL(Interface Definition Language)文件定义服务接口的参数和返回值类型,然后通过代码生成程序生成服务端和客户端的具体实现代码,这样在 gRPC 里,客户端应用可以像调用本地对象一样调用另一台服务器上对应的方法。
1.2特点
- 通信协议采用了 HTTP/2,因为 HTTP/2 提供了连接复用、双向流、服务器推送、请求优先级、首部压缩等机制
- IDL 使用了ProtoBuf,ProtoBuf 是由 Google 开发的一种数据序列化协议,它的压缩和传输效率极高,语法也简单
- 多语言支持,能够基于多种语言自动生成对应语言的客户端和服务端的代码。
1.3Protobuf文件
-
syntax
用来指定protobuf的版本 -
java_multiple_files
是否多个文件 -
java_package
生成文件包路径
-
java_outer_classname
文件名
-
方法
-
参数
-
数据类型
-
服务类型
简单rpc:就是一般的rpc调用,一个请求对象对应一个返回对象
proto语法:rpc simpleHello(Person) returns (Result) {}
服务端流式rpc:一个请求对象,服务端可以传回多个结果对象
proto语法:rpc serverStreamHello(Person) returns (stream Result) {}
客户端流式rpc:客户端传入多个请求对象,服务端返回一个响应结果
proto语法:rpc clientStreamHello(stream Person) returns (Result) {}
双向流式rpc:结合客户端流式rpc和服务端流式rpc,可以传入多个对象,返回多个响应对象
proto语法:rpc biStreamHello(stream Person) returns (stream Result) {} -
常用的调用方式
1)DialogServiceBlockingStub(阻塞,类似http,一个请求,一个响应)
2)DialogServiceStub(异步调用)
2.整合springboot
2.1项目结构
- springboot_grpc
父类项目 - grpc_client
grpc客户端 - grpc_server
grpc 服务端 - grpc_lib
公共jar包
2.2pom配置
- 父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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gz</groupId>
<artifactId>springboot_grpc</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>springboot_grpc</name>
<properties>
<java.version>1.8</java.version>
<grpc-client.version>2.10.1.RELEASE</grpc-client.version>
<grpc-server.version>2.10.1.RELEASE</grpc-server.version>
</properties>
<packaging>pom</packaging>
<modules>
<module>grpc_client</module>
<module>grpc_server</module>
<module>grpc_lib</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>${grpc-client.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>${grpc-server.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 客户端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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gz</groupId>
<artifactId>springboot_grpc</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.gz</groupId>
<artifactId>grpc_client</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>grpc_client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.gz</groupId>
<artifactId>grpc_lib</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 服务端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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gz</groupId>
<artifactId>springboot_grpc</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.gz</groupId>
<artifactId>grpc_server</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>grpc_server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.gz</groupId>
<artifactId>grpc_lib</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 公共lib 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.gz</groupId>
<artifactId>springboot_grpc</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<groupId>com.gz</groupId>
<artifactId>grpc_lib</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>grpc_lib</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<dubbo.protobuf.verion>2.7.14</dubbo.protobuf.verion>
<dubbo.compiler.version>0.0.2</dubbo.compiler.version>
<grpc.version>1.6.1</grpc.version>
<protobuf.version>3.3.0</protobuf.version>
<protobuf.format.version>1.2</protobuf.format.version>
</properties>
<dependencies>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<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.5.0</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
<outputDirectory>src/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.3proto文件
- 创建文件
创建文件夹要和java文件夹同目录
创建proto文件
syntax = "proto3";
option java_multiple_files = false;
option java_package = "com.gz.grpc_lib.protobuf";
option java_outer_classname="HelloServiceProto";
service HelloService {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc SayHelloBothStream (stream SteamRequest) returns (stream SteamReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
message SteamRequest {
string name = 1;
}
message SteamReply {
string message = 1;
}
- 创建grpc
通过maven 插件创建,点击编译,再点击custom
2.4服务端
- application.yml
grpc:
server:
port: 9999
spring:
application:
name: grpc-server
server:
port: 8888
- 服务代码
package com.gz.grpc_server.service.grpc;
import com.gz.grpc_lib.protobuf.HelloServiceGrpc;
import com.gz.grpc_lib.protobuf.HelloServiceProto;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
/**
* @author GuoZhong
* @description
* @date 2022/12/9 10:34
*/
@GrpcService
@Slf4j
public class UserInfoServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
@Override
public void sayHello(HelloServiceProto.HelloRequest request, StreamObserver<HelloServiceProto.HelloReply> responseObserver) {
String name = request.getName();
//构建响应值
HelloServiceProto.HelloReply.Builder response=HelloServiceProto.HelloReply.newBuilder();
response.setMessage("hello every one :"+name);
responseObserver.onNext(response.build());
responseObserver.onCompleted();
}
@Override
public StreamObserver<HelloServiceProto.SteamRequest> sayHelloBothStream(StreamObserver<HelloServiceProto.SteamReply> responseObserver) {
return new StreamObserver<HelloServiceProto.SteamRequest>() {
@Override
public void onNext(HelloServiceProto.SteamRequest steamRequest) {
log.info("正在处理");
responseObserver.onNext(HelloServiceProto.SteamReply.newBuilder()
.setMessage(steamRequest.getName())
.build());
}
@Override
public void onError(Throwable throwable) {
log.info("异常",throwable);
}
@Override
public void onCompleted() {
log.info("完成");
responseObserver.onCompleted();
}
};
}
}
2.5客户端
- application.yml
grpc:
client:
grpc-server:
address: static://localhost:9999
enableKeepAlive: true
keepAliveWithoutCalls: true
negotiationType: plaintext
spring:
application:
name: grpc-client
server:
port: 8891
- 代码
package com.gz.grpc_client.controller;
import com.gz.grpc_lib.protobuf.HelloServiceGrpc;
import com.gz.grpc_lib.protobuf.HelloServiceProto;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
/**
* @author GuoZhong
* @description
* @date 2022/12/9 11:03
*/
@RestController
@RequestMapping("/test")
public class HelloController {
@GrpcClient("grpc-server")
HelloServiceGrpc.HelloServiceFutureStub helloServiceFutureStub;
@GrpcClient("grpc-server")
HelloServiceGrpc.HelloServiceStub helloServiceStub;
@GetMapping("hello")
public String hello(@PathVariable String name) throws ExecutionException, InterruptedException {
String str=helloServiceFutureStub.sayHello(HelloServiceProto.HelloRequest.newBuilder().setName(name).build()).get().getMessage();
return str;
}
@GetMapping("moreStream")
public void moreStream( ) {
//接受服务端消息
StreamObserver<DialogServiceProto.MoreInvokeDlgStreamResponse> responseObserver =
new StreamObserver<DialogServiceProto.MoreInvokeDlgStreamResponse>() {
@Override
public void onNext(DialogServiceProto.MoreInvokeDlgStreamResponse moreInvokeDlgStreamReply) {
log.info("客户接收信息:{}",moreInvokeDlgStreamReply.getMsg());
}
@Override
public void onError(Throwable throwable) {
log.info("异常", throwable);
}
@Override
public void onCompleted() {
log.info("完成");
}
};
//发送服务端口消息
StreamObserver<DialogServiceProto.MoreInvokeDlgStreamRequest> requestObserver = dialogServiceStub
.moreInvokeDlgStream(responseObserver);
for(int i=1; i <= 10; i++){
// 发送一笔数据到服务端
requestObserver.onNext(DialogServiceProto.MoreInvokeDlgStreamRequest.newBuilder()
.setUuid("测试"+i)
.build());
log.info("客户端发送数据:{}","测试"+i);
}
}
}