@[toc]
目录
安装protocbuf
下载地址
https://github.com/protocolbuffers/protobuf/releases
选择对应的版本下载安装,这里我选择21.1
选择对应的压缩包解压

配置环境变量
变量名 :PROTOCBUF_HOME
变量值:D:\protoc-21.1-win64

找到系统变量中的path变量,选中后点击编辑,新增:%PROTOBUF_HOME%\bin
安装protocbuf插件
Protobuf - IntelliJ IDEs Plugin | Marketplace
从idea官网下载插件

选择idea对应的版本下载

项目目录结构

项目结构

创建maven父工程spring-boot-grpc
完整pom.xml
- <?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>
- <packaging>pom</packaging>
-
- <modules>
- <module>spring-boot-grpc-lib</module>
- <module>local-server</module>
- <module>local-client</module>
- </modules>
-
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.6.1</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>org.example</groupId>
- <artifactId>spring-boot-grpc</artifactId>
- <version>1.0-SNAPSHOT</version>
-
- <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>
-
- </dependencies>
-
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.8.1</version>
- <configuration>
- <source>1.8</source>
- <target>1.8</target>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <version>2.6.1</version>
- </plugin>
- </plugins>
- </build>
- </project>
创建模块spring-boot-grpc-lib
此模块负责将.proto文件生成Java对应的类与接口
根据官方文档
选择对应的版本查看README.md
可以根据提交历史查看具体proto版本对应的pom.xml
完整pom.xml
- <?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">
- <parent>
- <groupId>org.example</groupId>
- <artifactId>spring-boot-grpc</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.example</groupId>
- <artifactId>spring-boot-grpc-lib</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>spring-boot-grpc-lib</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>io.grpc</groupId>
- <artifactId>grpc-netty-shaded</artifactId>
- <version>1.42.1</version>
- </dependency>
- <dependency>
- <groupId>io.grpc</groupId>
- <artifactId>grpc-protobuf</artifactId>
- <version>1.42.1</version>
- </dependency>
- <dependency>
- <groupId>io.grpc</groupId>
- <artifactId>grpc-stub</artifactId>
- <version>1.42.1</version>
- </dependency>
- <dependency> <!-- necessary for Java 9+ -->
- <groupId>org.apache.tomcat</groupId>
- <artifactId>annotations-api</artifactId>
- <version>6.0.53</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>com.google.protobuf</groupId>
- <artifactId>protobuf-java</artifactId>
- <version>3.17.2</version>
- </dependency>
- <dependency>
- <groupId>com.google.protobuf</groupId>
- <artifactId>protobuf-java-util</artifactId>
- <version>3.17.2</version>
- </dependency>
- <dependency>
- <groupId>javax.annotation</groupId>
- <artifactId>javax.annotation-api</artifactId>
- <version>1.3.2</version>
- </dependency>
- </dependencies>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>io.grpc</groupId>
- <artifactId>grpc-bom</artifactId>
- <version>1.42.2</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
- <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.6.1</version>
- <configuration>
- <protocArtifact>com.google.protobuf:protoc:3.17.2:exe:${os.detected.classifier}</protocArtifact>
- <pluginId>grpc-java</pluginId>
- <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.42.1:exe:${os.detected.classifier}</pluginArtifact>
- </configuration>
- <executions>
- <execution>
- <goals>
- <goal>compile</goal>
- <goal>compile-custom</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </project>
在spring-boot-grpc-lib模块的src/main/proto目录下新增名为helloworld.proto的文件
这里面定义了一个gRPC服务,里面含有一个接口,并且还有这个接口的入参和返回结果的定义
proto文件夹需要在 File -> ProjectStructure 中将其标记为sources

helloworld.proto完整代码
- syntax = "proto3"; // 协议版本
-
- // 选项配置
- option java_multiple_files = true;
- option java_package = "com.example.springbootgrpclib.grpc.protobuf";
- option java_outer_classname = "SimpleProto";
-
- service Simple {
- // 简单gRPC
- rpc OneToOne (MyRequest) returns (MyResponse) {
- }
- }
-
- message MyRequest {
- string name = 1;
-
- int32 value = 2;
- }
-
- message MyResponse {
- string message = 1;
-
- int64 result = 2;
- }
idea 单击编译类

生成对应的类并且将其复制到spring-boot-grpc-lib下

spring-boot-grpc-lib结构:

在父工程下面新建名为local-server的springboot模块,
添加gRPC 服务端 Maven 依赖和spring-boot-grpc-lib模块
完整pom.xml
- <?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.example</groupId>
- <artifactId>spring-boot-grpc</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <groupId>com.example</groupId>
- <artifactId>local-server</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>local-server</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>11</java.version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <spring-boot.version>2.6.1</spring-boot.version>
- </properties>
-
- <dependencies>
- <!--Lombok引入-->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <!--gRPC服务端-->
- <dependency>
- <groupId>net.devh</groupId>
- <artifactId>grpc-server-spring-boot-starter</artifactId>
- <version>2.13.0.RELEASE</version>
- </dependency>
- <!--spring-boot-grpc-lib模块-->
- <dependency>
- <groupId>com.example</groupId>
- <artifactId>spring-boot-grpc-lib</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
- </dependencies>
- </project>
springboot配置文件 application.yml
- spring:
- application:
- name: spring-boot-grpc-server
- # gRPC有关的配置,这里只需要配置服务端口号
- grpc:
- server:
- port: 9898
- server:
- port: 8080
增加启动类RpcServerApplication
- package com.example.localserver;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
-
- @SpringBootApplication
- public class RpcServerApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(RpcServerApplication.class, args);
- }
-
- }
在service类中将gRPC服务对外暴露出去
完整代码如下
- package com.example.localserver.server;
-
- import com.example.springbootgrpclib.grpc.protobuf.MyRequest;
- import com.example.springbootgrpclib.grpc.protobuf.MyResponse;
- import com.example.springbootgrpclib.grpc.protobuf.SimpleGrpc;
- import io.grpc.stub.StreamObserver;
- import lombok.extern.slf4j.Slf4j;
- import net.devh.boot.grpc.server.service.GrpcService;
-
-
- @GrpcService
- @Slf4j
- public class GrpcServerService extends SimpleGrpc.SimpleImplBase {
-
- @Override
- public void oneToOne(MyRequest request, StreamObserver<MyResponse> responseObserver) {
- log.info("接收客户端数据{}", request);
- MyResponse response = MyResponse.newBuilder().setMessage( request.getName()).build();
- responseObserver.onNext(response);
- responseObserver.onCompleted();
- }
-
- }
上述GrpcServerService.java中有几处需要注意:
是使用@GrpcService注解,再继承SimpleImplBase,这样就可以借助grpc-server-spring-boot-starter库将oneToOne暴露为gRPC服务;
SimpleImplBase是前文中根据proto自动生成的java代码,在spring-boot-grpc-lib模块中;
oneToOne方法中处理完毕业务逻辑后,调用responseObserver.onNext方法填入返回内容;
调用responseObserver.onCompleted方法表示本次gRPC服务完成;
至此,gRPC服务端编码就完成了,服务端流、客户端流和双向流在后面介绍。
在父工程grpc-turtorials下面新建名为local-client的模块
添加gRPC客户端 Maven 依赖和spring-boot-grpc-lib模块
完整pom.xml
- <?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.example</groupId>
- <artifactId>spring-boot-grpc</artifactId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <groupId>com.example</groupId>
- <artifactId>local-client</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>local-client</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>11</java.version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <spring-boot.version>2.6.1</spring-boot.version>
- </properties>
-
- <dependencies>
-
- <!--gRPC客户端-->
- <dependency>
- <groupId>net.devh</groupId>
- <artifactId>grpc-client-spring-boot-starter</artifactId>
- <version>2.13.0.RELEASE</version>
- </dependency>
- <!--spring-boot-grpc-lib模块-->
- <dependency>
- <groupId>com.example</groupId>
- <artifactId>spring-boot-grpc-lib</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </dependency>
- <!--lombok-->
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- </dependencies>
- </project>
springboot配置文件 application.yml:
- server:
- port: 8088
- spring:
- application:
- name: local-client
-
- grpc:
- client:
- # gRPC配置的名字,GrpcClient注解会用到
- local-grpc-server:
- # gRPC服务端地址
- address: 'static://127.0.0.1:9898'
- enableKeepAlive: true
- keepAliveWithoutCalls: true
- negotiationType: plaintext
启动类RpcClientApplication
- package com.example.localclient;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
-
- @SpringBootApplication
- public class RpcClientApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(RpcClientApplication.class, args);
- }
-
- }
服务类GrpcClientService
- package com.example.localclient.service;
-
- import com.example.springbootgrpclib.grpc.protobuf.MyRequest;
- import com.example.springbootgrpclib.grpc.protobuf.MyResponse;
- import com.example.springbootgrpclib.grpc.protobuf.SimpleGrpc;
- import io.grpc.StatusRuntimeException;
- import lombok.extern.slf4j.Slf4j;
- import net.devh.boot.grpc.client.inject.GrpcClient;
- import org.springframework.stereotype.Service;
-
- @Service
- @Slf4j
- public class GrpcClientService {
-
- @GrpcClient("local-grpc-server")
- private SimpleGrpc.SimpleBlockingStub simpleStub;
-
- public String oneToOne(final String name) {
- try {
- final MyResponse response = this.simpleStub.oneToOne(MyRequest.newBuilder().setName(name).build());
- return response.getMessage();
- } catch (final StatusRuntimeException e) {
- return "FAILED with " + e.getStatus().getCode().name();
- }
- }
- }
上述GrpcClientService类有几处要注意的地方:
用@Service将GrpcClientService注册为spring的普通bean实例;
用@GrpcClient修饰SimpleBlockingStub,这样就可以通过grpc-client-spring-boot-starter库发起gRPC调用,被调用的服务端信息来自名为local-grpc-server的配置;
SimpleBlockingStub来自前文中根据helloworld.proto生成的java代码;
SimpleBlockingStub.oneToOne方法会远程调用local-server应用的gRPC服务;
新增controller层验证gRPC服务调用能否成功
- package com.example.localclient.controller;
-
- import com.example.localclient.service.GrpcClientService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.bind.annotation.RestController;
-
- import java.util.List;
-
- /**
- * @author cdj
- * @date 2022/4/11 - 17:36
- **/
- @RestController
- public class GrpcClientController {
-
- @Autowired
- private GrpcClientService grpcClientService;
-
- @RequestMapping("/oneToOne")
- public String oneToOne(@RequestParam(defaultValue = "name") String name) {
- return grpcClientService.oneToOne(name);
- }
-
- }
http://127.0.0.1:8088/oneToOne?name=rpc-test
