简介
gRPC 是 google 开源的一个高性能、跨语言的 RPC 框架,基于 HTTP2 协议,基于 protobuf 3.x,基于 Netty 4.x +。
对于开发者而言:
1)需要使用 protobuf 定义接口,即.proto 文件。
2)然后使用 compile 工具生成特定语言的执行代码,比如 JAVA、C/C++、Python 等。类似于 thrift,为了解决跨语言问题。
3)启动一个 Server 端,server 端通过侦听指定的 port,来等待 Client 链接请求,通常使用 Netty 来构建,GRPC 内置了 Netty 的支持。
4)启动一个或者多个 Client 端,Client 也是基于 Netty,Client 通过与 Server 建立 TCP 常链接,并发送请求;Request 与 Response 均被封装成 HTTP2 的 stream Frame,通过 Netty Channel 进行交互。
proto3
编写 proto3 文件
文件命名为 pb.proto。
根据 proto 生成代码
-
创建一个空的项目。
-
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>proto</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jackson.version>2.8.3</jackson.version>
<grpc.version>1.6.1</grpc.version>
<os.plugin.version>1.5.0.Final</os.plugin.version>
<protobuf.plugin.version>0.5.0</protobuf.plugin.version>
<protoc.version>3.3.0</protoc.version>
<grpc.netty.version>4.1.14.Final</grpc.netty.version>
</properties>
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${grpc.netty.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os.plugin.version}</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf.plugin.version}</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
-
java 同级目录下添加 proto 目录,将编写好的 proto 文件放到该目录下。
-
依次执行 mvn 命令 protobuf:compile 和 protobuf:compile-custom 编译生成 java 文件。
-
生成后的文件存放在 target 目录下。
可以对比看出,生成的 java 文件和 proto 文件中定义的 service 和 message 是对应的。其中 option java_multiple_files = true;
配置决定是将 message 定义为一个文件还是内部类,将配置修改为 false 后再次执行 mvn 命令后会发现生成的文件变成以下这种,这就是把 message 定义为了内部类。不过这两种对功能上并无影响,开发者可以自行选择。
推荐将生成代码的项目单独存放,不要合并到开发项目中。因为 pom 中引入的 jar 和插件只是为了生成代码,后续在 SpringBoot 中使用 gRPC 并不需要这些 jar。示例项目放到了 96XL/proto: proto 文件生成 (github.com),需要的可以自取。
SpringBoot 整合
生成代码的项目、服务端项目、客户端项目三者可以完全分离,单独使用哪个项目都可以。例如使用服务端给外部系统提供 gRPC 接口,或者使用客户端调用外部系统的 gRPC 接口。
服务端
-
添加 maven 依赖。
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.13.1.RELEASE</version>
</dependency>
-
服务端代码(记得将生成的类加到项目中)。
@Slf4j
@GrpcService
public class UserGrpcServer extends UserServiceGrpc.UserServiceImplBase {
public void register(UserServiceProto.RegisterReq request, StreamObserver<UserServiceProto.RegisterRsp> responseObserver) {
// 接收到的参数
log.info(request.toString());
// 响应
UserServiceProto.RegisterRsp reply = UserServiceProto.RegisterRsp.newBuilder().setCode(0).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
-
配置文件添加配置。
grpc:
server:
port: 7777
客户端
- 添加 maven 依赖。
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.13.1.RELEASE</version>
</dependency>
- 客户端代码(记得将生成的类加到项目中)。
@Service
public class UserGrpcClient {
@GrpcClient("userServiceGrpc")
private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;
public void register(String phone, String userId) {
UserServiceProto.RegisterReq registerReq = UserServiceProto.RegisterReq.newBuilder().setPhone(phone).setUserId(userId).build();
userServiceBlockingStub.register(registerReq);
}
}
- 配置文件添加配置。这里的 IP 就是服务端的 IP,端口号要和服务端指定的端口号保持一致。userServiceGrpc 就是客户端代码
@GrpcClient("userServiceGrpc")
中指定的值,两者保持一致即可,和服务端没有关系。
grpc:
client:
userServiceGrpc:
address: static://localhost:7777
negotiationType: PLAINTEXT
- 接口中正常调用方法即可。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于