述
gRPC 是谷歌的一个开源 RPC 框架, 因为最近要做一个跨语言平台的交互,所以选用了 gRPC 这个框架,下面记录一下从零开始跟 Spring Boot 集成的过程.
proto文件编写
使用 gRPC 第一步,要先编写一个 .proto 文件,这个文件的作用是定义接口的一些入参返回值等等,比如下面这个 HelloWorld.proto
文件
1 | syntax = "proto3"; |
syntax
第一行 syntax = "proto3";
这个是定义这个 proto 文件的版本, 如果学过 docker 的话就不难理解,我们编写 dockerfile 的时候也要定义一下 version 版本号, 这里要注意的是,这个版本要跟你引入的jar包的版本匹配,不然编译之后会有很多包找不到
option
选项, 这个相当于一个配置, 比如上面文件中的 option java_multiple_files = true;
这个配置表示:指定在 proto 文件中定义的所有消息,枚举和服务在生成java类的时候都会生成对应的java类文件,而不是以内部类的形式出现.
到这儿可能有点懵,先来了解一下这个 proto 文件使用的整体流程:
- 编写 proto 文件,定义方法名,入参出参等基本信息
- 通过工具编译 proto 文件,这步操作会生成一堆 java 类, 对应的就有我们上面定义的入参的model,出参的model, 以及构建入参出参的一些工具类等等
- 把生成的类复制到我们的项目中, 然后编写实现类, 实现类中就是我们具体的业务逻辑
- 启动服务端,提供给客户端访问
到这儿应该能理解 option java_multiple_files = true;
这个配置的作用了吧, 就是如果配置的是 false, 他会把所有需要的类都放到一个 java 类中, 以内部类的形式存在, 如果设置的是 true 的话, 那就会各生成各的.
option 这个设置还有别的项, Google 一下都有
message
message 这个是消息定义,可以理解为 Java 中的实体类, 声明实体类,然后定义类中的属性. 字段类型跟java中的基本类型差不多,稍微有点不一样,这个可以 Google 一下.
这里要注意一点,上面我们定义的字段 string txt = 1;
这个 1 并不是这个字段的初始值,而是给这个字段分配的标量, 每一个被定义在消息中的字段都会被分配给一个唯一的标量,这些标量用于标识你定义在二进制消息格式中的属性,标量一旦被定义就不允许在使用过程中再次被改变,标量的值在1~15的这个范围里占一个字节编码.
service
这个就相当于定义一个 Java 中的接口, 然后下面的 rpc 是定义具体的接口名以及入参出参, 这部分应该比较好理解
引入依赖
现在 Java 项目基本都是用 spring boot 了吧, 所以找一个开源的 starter 可以帮我们快速集成 grpc 需要用到的一些配置, 引入下面这个包
1 | <dependency> |
这个项目的GitHub在这里
包导入之后,还需要加一个插件用来把 proto 文件编译成我们需要的 java 文件,插件导入如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30<build>
<finalName>grpc-java</finalName>
<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.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.11.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.27.2:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
编译代码
上面配置完成之后,使用 mvn clean generate-sources
命令编译 proto 文件, 然后在如下文件夹中可以找到编译结果
这些类需要复制到我们的项目对应的包中
编写实现类
上面生成的只是一些接口,构建请求返回的工具类等等, 具体的业务逻辑我们还没有写, 新建一个类,继承 HelloServiceGrpc.HelloServiceImplBase
, 继承的这个类是我们上面自动生成的, 找后缀是 Grpc 的, 然后内部类以 ImplBase 后缀结尾的这个
之后重写我们的业务方法, 具体代码如下:
1 | @GRpcService |
这里入参出参就都可以拿到了,这个方法里可以写具体的业务逻辑,比如连接数据库,增删改查等等
服务启动
在上面的实现类中,加入 @GRpcService
这个注解,之后就会被容器扫描到,然后对外提供服务, 默认的接口是 5656 , 可以在配置文件中通过 grpc.server.port
这个值修改
到这儿服务端方面的东西就OK了, 一般我们为了不被打, 写完接口还得自测一下嘛, 所以还需要看看客户端的一些配置
客户端配置
客户端需要一个配置类,如下:
1 | @Configuration |
这个类就是设置一个 channel ,配置地址,当然这个地址可以写在配置文件里, 然后还要 @Bean
注入一个类, 是 Grpc 结尾然后 BlockingStub 结尾的内部类, 注入到容器中, 之后就可以在单元测试或者别的地方使用了
1 | @Autowired |
导入公共类
定义 proto 文件的时候,像上面这种 HelloResponse
的 message 其实是通用的,就可以单独用一个文件定义一下,然后用 import 关键字导入进来, 就不用在每个文件中都写一次了,如下:
1 | import "common/CommonResponse.proto"; |
这里有一点主意的是,只能用绝对路劲,不能使用 ./ 或者 ../ 这种,否则编译会报错
以上就是 grpc 的一个简单的示例,更高级的用法可以看一下 grpc-spring-boot-starter
的 GitHub,这个里面提供了很多的示例
就先记到这儿,下课.