简介
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。
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.example.entity";
option java_outer_classname = "UserServiceProto";
service UserService {
// 注册接口
rpc register(RegisterReq) returns (RegisterRsp);
}
message RegisterReq {
// 手机号
string Phone = 1;
// 用户ID
string UserId = 2;
}
message RegisterRsp {
// 业务状态码
int32 code = 1;
// 信息
string msg = 2;
}
根据 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
- 接口中正常调用方法即可。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于