SpringBoot 之整合gRPC

embedded/2024/11/19 19:51:43/

父工程中引入基本的依赖:

<modules><module>api</module><module>client</module><module>service</module></modules><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.7.3</version>
</parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>
</dependencies>

API模块(定义proto文件):

<artifactId>grpc-api</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging><properties><grpc.version>1.6.1</grpc.version><protobuf.version>3.3.0</protobuf.version>
</properties><dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-netty</artifactId><version>${grpc.version}</version><scope>provided</scope></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>${grpc.version}</version><scope>provided</scope></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>${grpc.version}</version><scope>provided</scope></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf.version}</version></dependency>
</dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.5.0.Final</version></extension></extensions><plugins><!-- 引入一些插件来帮助我们将.proto文件编译为java的类 --><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.5.0</version><configuration><!--使用的protoc版本,os.detected.classifier表示检测到的操作系统,这里检测到的是windows-x86_64--><protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact><!--proto文件所在文件夹的位置--><protoSourceRoot>src/main/proto</protoSourceRoot><!--生成的文件的存放位置 --><outputDirectory>src/main/java</outputDirectory><!--在调用插件去生成java类时,是否清空输出文件夹,这个要设置为false,否则运行compile-custom时会把compile的结果给删了--><clearOutputDirectory>false</clearOutputDirectory></configuration><!-- 做的一个扩展,在执行maven的compile的时候,顺便也执行protobuf-maven-plugin插件的compile和compile-custom--><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins>
</build>

在src/main目录下创建proto文件夹。
创建一个HelloWorldService.proto文件。
在这里插入图片描述

//使用proto3语法
syntax = "proto3";//生成多个java文件
option java_multiple_files = true;
//把生成的文件放到哪个包下
option java_package = "com.gotion.grpc.api";
//输出的类名
option java_outer_classname = "HelloWorldServiceProto";//定义一个类
service HelloWorldService {//定义一个gRPC方法,参数为HelloRequest,返回结果为HelloResponserpc helloWorld(HelloRequest) returns(HelloResponse) {};
}
//定义的一个请求参数对象
message HelloRequest {//msg参数,编号为1,这是编号不是赋值string msg = 1;//code参数,编号为2int32 code = 2;
}
//定义的一个返回结果对象
message HelloResponse {//resut参数,编号为1string result = 1;
}

将proto文件编译成需要的JAVA文件(使用maven去compile)了。

server模块:

<dependencies><!-- 引入api模块--><dependency><groupId>com.gotion</groupId><artifactId>grpc-api</artifactId><version>1.0.0</version></dependency><!--  引入gRPC服务提供端依赖--><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>2.14.0.RELEASE</version></dependency>
</dependencies>

application.yml文件:

server:port: 8081 #正常的SpringBoot应用监听的端口号grpc:server:port: 9081 #gRPC服务监听的端口号

编写启动类。
实现在API模块中定义的gRPC服务。

java">import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;/*** gRPC服务提供类,继承api模块中的proto文件编译生成的java文件,重写所定义的gRPC方法*/
@GrpcService
@Slf4j
public class HelloWorldService extends HelloWorldServiceGrpc.HelloWorldServiceImplBase {/*** 定义的gRPC方法** @param request          请求对象* @param responseObserver*/@Overridepublic void helloWorld(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {//解析请求,获取其中的参数,这些都是我们之前在proto文件中定义的String msg = request.getMsg();int code = request.getCode();log.info("请求中的参数为msg:{},code:{}", msg, code);//创建一个响应对象HelloResponse helloResponse = HelloResponse.newBuilder().setResult("我是server服务端,我收到了你的请求~").build();//将该响应对象返回给调用者responseObserver.onNext(helloResponse);//这次调用结束了responseObserver.onCompleted();}
}

client端:

<dependencies><!-- spring boot web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 引入api模块--><dependency><groupId>com.gotion</groupId><artifactId>grpc-api</artifactId><version>1.0.0</version></dependency><!-- 引入gRPC客户端依赖--><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>2.14.0.RELEASE</version></dependency>
</dependencies>

application.yml文件:

server:port: 8080 #springboot应用监听的端口号
grpc:client:# 自定义服务名(不同服务名可对应不同配置)GrpcClient注解会用到grpc-server:# 服务端地址,9081是服务提供方的gRPC监听的端口号address: localhost:9081# 是否开启保持连接(长连接)enable-keep-alive: true# 使用明文传输negotiation-type: plaintext

编写启动类。
测试服务调用(阻塞方式和异步方式)。

java">import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/*** 测试gRPC服务调用*/
@RestController
@Slf4j
@RequestMapping("/client")
public class TestController {//注入阻塞型的gRPC调用对象,服务调用的地址在application.yml中设置了@GrpcClient("grpc-server")private HelloWorldServiceGrpc.HelloWorldServiceBlockingStub blockingStub;//注入异步调用的gRPC调用对象@GrpcClient("grpc-server")private HelloWorldServiceGrpc.HelloWorldServiceFutureStub futureStub;//创建一个线程池来进行异步调用private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20,0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(50), new ThreadPoolExecutor.CallerRunsPolicy());//用来接收异步调用结果private String result;/*** 测试阻塞调用** @return 调用结果*/@GetMapping("/block")public String block() {//构造请求对象HelloRequest helloRequest = HelloRequest.newBuilder().setMsg("block").setCode(100).build();//进行阻塞式地调用HelloResponse helloResponse = blockingStub.helloWorld(helloRequest);return helloResponse.getResult();}/*** 测试异步调用** @return 调用结果*/@GetMapping("/future")public String future() throws InterruptedException {//构造请求对象HelloRequest helloRequest = HelloRequest.newBuilder().setMsg("block").setCode(100).build();//进行异步调用,看到这里返回的是一个ListenableFuture,大家应该都知道要怎么做了哈哈哈ListenableFuture<HelloResponse> helloResponseListenableFuture = futureStub.helloWorld(helloRequest);//创建一个CountDownLatch,来等待所有的异步任务完成(如果要执行多个异步任务的话,这里只是用一下)//参数为要等待执行的异步任务数,这里是1,其实就是一个计算器CountDownLatch countDownLatch = new CountDownLatch(1);//设置回调Futures.addCallback(helloResponseListenableFuture,new FutureCallback<HelloResponse>() {@Overridepublic void onSuccess(HelloResponse helloResponse) {log.info("异步调用成功了,结果为{}", helloResponse.getResult());result = helloResponse.getResult();//计数器减1,表示该异步任务执行完成countDownLatch.countDown();}@Overridepublic void onFailure(Throwable throwable) {log.error("异步调用失败,原因是{}", throwable.getMessage());}},executor);//为了更直观地表现出异步任务,这里打印一个日志log.info("这里是主线程");//等待所有异步任务执行完成countDownLatch.await();return result;}
}

http://www.ppmy.cn/embedded/138849.html

相关文章

百度世界2024|李彦宏:智能体是AI应用的最主流形态,即将迎来爆发点

“ 过去24个月&#xff0c;AI行业的最大变化是什么&#xff1f;是大模型基本消除了幻觉。” 11月12日&#xff0c;百度创始人李彦宏在百度世界2024大会上&#xff0c;发表了主题为《应用来了》的演讲&#xff0c;发布两大赋能应用的AI技术——检索增强的文生图技术&#xff08;…

【java】抽象类和接口(了解,进阶,到全部掌握)

各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连&#xff0c;小编尽全力做到更好 欢迎您分享给更多人哦 大家好我们今天来学习Java面向对象的的抽象类和接口&#xff0c;我们大家庭已经来啦~ 第一次复习时总结&#xff1a; 一&#xff1a;抽象类 1.1…

基于 PyTorch 从零手搓一个GPT Transformer 对话大模型

一、从零手实现 GPT Transformer 模型架构 近年来&#xff0c;大模型的发展势头迅猛&#xff0c;成为了人工智能领域的研究热点。大模型以其强大的语言理解和生成能力&#xff0c;在自然语言处理、机器翻译、文本生成等多个领域取得了显著的成果。但这些都离不开其背后的核心架…

Qt-QWidget中的属性和方法

控件简单概述 控件Wigdet&#xff0c;其实也就是小组件/小部件的意思&#xff0c;但是读作控件就显得非常专业了。 在Qt Designer中 这些都是Qt给我们内置好的类。 Qt中的各种控件都是继承自QWidget类&#xff0c;并且在QWidget这里可以看到控件的属性&#xff1a; QWidget …

Asp.NET Core Mvc中一个视图怎么设置多个强数据类型

在ASP.NET Core MVC中&#xff0c;一个视图通常与一个强类型模型&#xff08;Model&#xff09;相关联。然而&#xff0c;在某些情况下&#xff0c;你可能需要在单个视图中使用多个不同的模型类型。为了实现这一点&#xff0c;你有几种选择&#xff1a; 使用视图模型&#xff0…

C语言常用语句总结

一:常用函数 1、putchar函数: putchar函数(字符输出函数):向终端输出一个字符。 一般形式为: putchar(c) // 输出字符变量c的值。 == printf(“%c”,c) 2、getchar函数 getchar函数(字符输入函数):从终端输入一个字符。 getchar函数没有参数,一般…

企业网络链路聚合、数据抓包、远程连接访问实验

前言&#xff1a; 随着信息技术的飞速发展和企业业务的不断扩大&#xff0c;企业网络面临着越来越多的挑战。其中&#xff0c;网络带宽、数据安全和远程访问等问题尤为突出。为了解决这些问题&#xff0c;我们进行了本次企业网络链路聚合、数据抓包和远程连接访问的实验。 链路…

图像重建之深度学习重建

图像重建是计算机视觉领域的一个重要任务。深度学习在图像重建中具有很强的能力和广泛的应用。下面介绍一种常见的深度学习图像重建方法&#xff1a;基于生成对抗网络&#xff08;Generative Adversarial Networks&#xff0c;GANs&#xff09;的图像重建。 基于 GAN 的图像重…