gRPC (gRPC Remote Procedure Calls) 是 Google 发起的一个开源远程过程调用系统,该系统基于 HTTP/2 协议传输,本文介绍 gRPC 的基础概念,首先通过关系图直观展示这些基础概念之间关联,介绍异步 gRPC 的 Server 和 Client 的逻辑;然后介绍 RPC 的类型,阅读和抓包分析 gRPC 的通信过程协议,gRPC 上下文;最后分析 grpc.pb.h 文件的内容,包括 Stub 的能力、Service 的种类以及与核心库的关系。(摘自知乎:https://zhuanlan.zhihu.com/p/389328756)
操作环境- 系统:ubuntu 18.04
- 架构:linux-x86_64
- 环境:JDK8 maven idea
- 仓库:阿里云maven
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准。他们用于 RPC 系统和持续数据存储系统。提供一个具有高效的协议数据交换格式工具库(类似Json)。
但相比于Json,Protobuf有更高的转化效率,时间效率和空间效率都是JSON的3-5倍。
可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 、OC、Swift等语言的 API。总只一句话就是很好,支持多平台且与语言无关。(https://www.jianshu.com/p/a24c88c0526a)
简单理解:protobuf是将后缀名为.proto的文件编译成各类语言API的编译工具
安装Protobuf执行命令:
sudo apt install protobuf-compiler
查看版本
protoc --version
创建项目 项目结构libprotoc 3.0.0
- grpc为maven父项目。
- grpc-lib为maven子项目,用于生成由protobuf编译的接口API。
- grpc-server为服务端SpringBoot子项目,负责实现接口功能。
- grcp-client为客户端Springboot子项目,负责调用服务端进行返回。
- 选择一个空的maven项目
- 删除src,使之成为一个空的父项目,这里面项目名为grpc-test,后续会使用grpc代替
- pom依赖
子模块构建-lib接口API 模块结构4.0.0 com.nces grpc pom 1.0-SNAPSHOT grpc-lib grpc-client grpc-server 8 8 1.43.1 1.0-SNAPSHOT 4.1.65.Final 2.3.7.RELEASE 3.0.0 3.8.1 1.18.16 com.nces grpc-lib ${lib-version} io.grpc grpc-netty ${grpc-version} io.grpc grpc-protobuf ${grpc-version} io.grpc grpc-stub ${grpc-version} io.netty netty-common ${netty-version} io.github.lognet grpc-spring-boot-starter ${grpc-spring-boot-starter.version} org.projectlombok lombok ${lombok-version}
模块结构
创建步骤├── pom.xml
└── src
└── main
├── java
│ └── GetClassifier.java 获取架构工具类,后续使用会详述
└── proto
└── HelloWorld.proto 用于生成接口proto文件
- 创建一个maven子项目
创建成功后子项目会引入父项目的坐标,同时,父项目会自动引入模块。如果没有,可以手动写进去
子项目
父项目
2.引入pom依赖
grpc com.nces 1.0-SNAPSHOT 4.0.0 grpc-lib 1.0-SNAPSHOT 8 8 linux-x86_64 io.grpc grpc-netty io.grpc grpc-protobuf io.grpc grpc-stub io.netty netty-common org.xolstice.maven.plugins protobuf-maven-plugin 0.6.1 com.google.protobuf:protoc:3.19.1:exe:${os.detected.classifier} grpc-java io.grpc:protoc-gen-grpc-java:1.43.1:exe:${os.detected.classifier} compile compile-custom org.apache.maven.plugins maven-compiler-plugin ${maven-plugin-version} 1.8 1.8 UTF-8
- 获取架构信息
写一个类,长期放在java文件夹下,方便其他人获取架构信息时直接调用
/grpc/grpc-lib/src/main/java
public class GetClassifier {
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
System.out.println(System.getProperty("os.arch"));
}
}
执行一下,得到结果
Linux
amd64
打开网站
查看架构关系
翻到readme中Generated properties部分
根据os.name查看osname
根据os.arch获取arch
组装得到linux-x86_64
将linux-x86_64配置到pom文件下properties下的
- 编写接口文件到src/main/proto中
syntax = "proto3";
option java_multiple_files = true;
option java_generic_services = true;
package com.grpc.grpcserver.server;
message Person {
string first_name = 1;
string last_name = 2;
}
message Greeting {
string message = 1;
}
service HelloWorldService {
rpc sayHello (Person) returns (Greeting);
}
- 右侧打开maven插件进行编译
- 编译结果
- 发布
将编译好的接口和实体进行打包发布
打开idea自带的控制台,会自动将目录指定到模块下
切换到lib模块
打包发布到本地maven仓库
cd grpc-lib/ mvn clean package install
查看是否打包成功
查看maven仓库坐标是否有该文件
server服务模块主要用于开放实现接口功能,开放端口给客户端使用
项目结构如图
- 创建一个经典的springboot模块,引入依赖
4.0.0 com.nces grpc-server 0.0.1-SNAPSHOT grpc-server grpc-server grpc com.nces 1.0-SNAPSHOT 1.8 UTF-8 UTF-8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine com.nces grpc-lib io.grpc grpc-netty io.grpc grpc-protobuf io.grpc grpc-stub io.netty netty-common io.github.lognet grpc-spring-boot-starter org.projectlombok lombok org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin ${maven-plugin-version} 1.8 1.8 UTF-8 org.springframework.boot spring-boot-maven-plugin 2.3.7.RELEASE com.nces.grpcserver.GrpcServerApplication repackage repackage
- application.properties配置服务端口
spring.application.name=grpc-server grpc.port=9099
- service实现
其中,@GRpcService声明是一个GRpc服务实现,使用它进行bean注入,就不能添加@Service一类的注解,否则会发生重复注入的情况
package com.nces.grpcserver.server;
import com.grpc.grpcserver.server.Greeting;
import com.grpc.grpcserver.server.HelloWorldServiceGrpc;
import com.grpc.grpcserver.server.Person;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.lognet.springboot.grpc.GRpcService;
@GRpcService
@Slf4j
public class HelloServer extends HelloWorldServiceGrpc.HelloWorldServiceImplbase {
@Override
public void sayHello(Person request, StreamObserver responseObserver) {
log.info("request:{}",request);
responseObserver.onNext(Greeting.newBuilder().setMessage("当前时间为"+System.currentTimeMillis()).build());
responseObserver.onCompleted();
}
}
- 启动服务端
客户端整合了spring-web,所以使用了传统的三层
- 创建一个空的springboot项目,引入依赖
4.0.0 com.nces grpc-client 0.0.1-SNAPSHOT grpc-client grpc-client grpc com.nces 1.0-SNAPSHOT 1.8 UTF-8 UTF-8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine com.nces grpc-lib org.projectlombok lombok org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin ${maven-plugin-version} 1.8 1.8 UTF-8 org.springframework.boot spring-boot-maven-plugin ${spring-boot.version} com.nces.grpcclient.GrpcClientApplication repackage repackage
- client客户端实现
package com.nces.grpcclient.client;
import com.grpc.grpcserver.server.Greeting;
import com.grpc.grpcserver.server.HelloWorldServiceGrpc;
import com.grpc.grpcserver.server.Person;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Slf4j
public class HelloWorldClient {
private HelloWorldServiceGrpc.HelloWorldServiceBlockingStub serviceBl;
@PostConstruct
public void init(){
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 9099).usePlaintext().build();
serviceBl = HelloWorldServiceGrpc.newBlockingStub(managedChannel);
}
public String sayHello(String firstName,String lastName){
Person person = Person.newBuilder().setFirstName(firstName).setLastName(lastName).build();
Greeting greeting = serviceBl.sayHello(person);
return greeting.getMessage();
}
}
- service层
package com.nces.grpcclient.service.impl;
import com.nces.grpcclient.client.HelloWorldClient;
import com.nces.grpcclient.service.HelloWorldService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class HelloWorldServiceImpl implements HelloWorldService {
@Resource
private HelloWorldClient client;
@Override
public String helloWorld(String beginName, String endName) {
return client.sayHello(beginName, endName);
}
}
- service接口
package com.nces.grpcclient.service;
public interface HelloWorldService {
String helloWorld(String beginName,String endName);
}
- controller
package com.nces.grpcclient.controller;
import com.nces.grpcclient.service.HelloWorldService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping(path = "/hello")
public class HelloWorldController {
@Resource
private HelloWorldService helloWorldService;
@GetMapping("/world")
public String helloWorld(String beginName,String endName){
return helloWorldService.helloWorld(beginName,endName);
}
}
- 启动客户端
URL:http://localhost:8080/hello/world?beginName=a&endName=b
server控制台
接口返回
如有疑问欢迎留言



