GRPC - JAVA笔记

GRPC - JAVA笔记

gRPC简介

  1. 由google开源的一个高性能的RPc框架,由google内部的Stubby框架演化而来。2015年正式开源。云原生时代的RPC标准,由Go语言开发

  2. gRPC的核心设计思路

    1. 网络通信 ------> gRPC 自己封装了网络通信的部分,提供了多种语言的 网络通信的封装,解决异构服务的问题 (C Java[Netty] Go)

    2. 协议 ------> HTTP2 传输数据的时候 使用二进制的数据内容。支持双向流(双工) 支持连接的多路复用

    3. 序列化 ------> 数据传输的格式,主要有两种 基于文本(JSON) 基于二进制 java原生的序列化方式

      ​ 谷歌开源的序列化方式:protubuf:Protocol Buffers 时间和空间效率是JSON的3-5倍

      ​ IDL语言

    4. 代理的创建 ----> 让调用者像调用本地方法那样,去调用远端的服务方法 称为 stub

  3. gPRC和ThriftRPC的区别

    共性:支持异构语言的RPC

    区别:

    ​ 网络通信 Thrift TCP 专属协议

    ​ GRPC HTTP2

    ​ 性能角度 ThriftRPC 性能高于 gRPC

    ​ gRPC 大厂支持,在云原生时代与其他组件更容易集成,所以gRPC应用更广泛

  4. gRPC的好处

    1. 高效的进行进程间通信 序列化和协议
    2. 支持多语言 原生支持 C Go Java (一等公民)实现,C语言版本上扩展 C++,C#,NodeJS,Python等(二等公民)
    3. 支持多平台运行
    4. GRPC采用protobuf
    5. 使用HTTP2协议(只有GRPC使用)

HTTP2.0 协议

1. 回顾HTTP1.x协议
     HTTP1.0 协议 请求响应的模式 短链接(无状态)协议 为了解决状态问题,使用了HttpSession的技术解决 单工通信  传输数据文本结构
     HTTP1.1 协议 请求响应的模式 有限长连接 CS连接会保持一段时间  升级到了WebSocket方式 双工 可以实现服务器向客户端推送
   总结Http1.x协议 共性
   	1. 传输数据文本格式,可读性好但是效率差
   	2. 本质上Http1.x无法实现双工通信
   	3. 资源的请求,需要发送多次请求,建立多个连接才可以完成
   		获取页面时,需要多次请求获取js和css文件,采用异步的方式进行。此时服务器压力增大,可以使用动静分离的手段解决,使用CDN缓存,减轻主服务器的请求压力
2. Http2.0协议
	1. HTTP2.0协议是一个二进制协议,效率高于Http1.0协议,但是可读性差
	2. 可以实现双工通信
	2. 一个请求,一个连接,可以请求多个数据 (多路复用)
3. Http2.0协议的三个概念(参看图)
	1. 数据流 stream
	2. 消息 message
	3. 帧 frame
4. 其他相关概念 (新的技术总是会把之前协议种使用程序来处理的问题放到标准中去)
	1. 数据流的优先级,可以通过位不同的stream设置权重,限制不同流的传输顺序
	2. 流控,client发送的数据太快了,服务器端处理不过来,通知client暂停数据发送

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DHPY2D2J-1683617948944)(D:\information\Typora笔记\学习笔记\grpc框架\GRPC - JAVA笔记.assets\image-20230429220152249.png)]

Protocol Buffers [protubuf]

1. protobuf 是一种与编程语言无关 [IDL],与具体的平台无关。它定义的中间语言,可以方便的在client与server种进行RPC的数据传输
2. protobuf两种版本,2和3,主要使用的是3
3. protobuf需要本地安装protubuf的编译器,将protobuf的IDL语言转换成一种特定的语言
4. protobuf编译器的安装:官方在最想版本没有提供windows的安装版本,可以考虑自己编译或者是降低版本去安装 https://github.com/protocolbuffers/protobuf/releases/v3.19.6
	1. 解压缩
	2. 配置环境变量
	3. cmd 输入 protoc --version 查看
5. idea 安装protobuf的插件,显示IDL语言提示
	idea 2022和2023 原生支持protobuf插件

Protobuf 语法详解

  • 文件格式

    文件一定要定义在以.proto结尾的文件中
    
    UserService.proto
    OrderService.proto
    
  • 版本设定

    syntax = "proto3"
    
  • 注释

    1. 单行注释 //
    2. 多行注释 /*   */
    
  • 与java相关的语法

    // 指定后续protobuf生成的java代码是一个源文件还是多个源文件 xx.java
    option java_multiple_files = false;
    
    // 指定protobuf生成的类放在那个包中
    option java_package = "indi.yuluo";
    
    // 指定protobuf生成的外部类的名字 (管理内部类【内部类才是真正开发使用的】)
    option java_outer_classname = "";
    
  • 逻辑包【java开发用的少】

    // protobuf对于文件内容的管理
    package xxx;
    
  • 导入

    // 在其他文件中导入其他的protobuf文件中定义的内容
    在OrderService.proto中使用UserService.proto中定义的内容
    
    import "xxx/UserService.proto";
    
  • 基本类型

    官方文档:https://protobuf.dev/programming-guides/proto3

  • 枚举

    enum SEASON {
    	SPRING = 0;
    	SUMMER = 1;
    }
    
    枚举的值必须从0开始
    
  • 消息 Message

    // 请求后缀为 Request 响应为Response
    message LoginRequest {
    	string username = 1;    // 消息中的字段编号
    	singular string password = 2;
    	int32 age = 3;
    }
    
    消息相关的细节问题
    1. 编号  从1开始到2^29-1,不一定连续  注意:19000-19999 编号不能使用,是protobuf自己保留的编号
    2. 在消息字符中可以加入两个关键字,
    	一个是 singular(这个字段的值只能是0或者1个,"" 或 "123456", 是默认关键字)
    	一个是repeated。起修饰字符的作用,字段返回值是多个,等价于 java中的List集合
    
    message Result {
    	string content = 1;
    	repeated string stutas = 2;  // 此字段的返回值是多个,等价于Java List
    }
    
    3. 消息可以定义多个
    message LoginRequest{
    	....
    }
    message LoginREsponse {
    	...
    }
    
    4. 消息可以嵌套
    message SearchResponse {
    
    	// 定义
    	message Result {
    		string url = 1;
    		string title = 2;
    	}
    	
    	string xxx = 1;
    	int32 yyy = 2;
    	// 上面所定义的字段
    	Result ppp = 3;
    }
    
    5. oneof关键字 [其中一个] 使用较少
    message SimpleMessage {
    	// 当我们使用test_oneof字段时,它得值只能是其中一个
    	oneof test_oneof {
    		string name = 1;
    		int32 age = 2;
    	}
    }
    
  • 服务定义

    service HelloService {
    	// HelloRequest是响应消息(message)
    	rpc hello(HelloRequest) returns(HelloRespose) {}
    }
    
    1. 里面可以定义多个服务方法
    2. 在开发过程中,可以定义多个服务接口
    3. gRPC服务有四种服务方
    

gRPC 开发实战

  • 项目结构

    1. xxx-api 模块 用于定义protobuf idl语言,并且通过命令创建具体的代码,后续client server引入使用
    	1. message	
    	2. service
    2. xxx-server 模块
    	1. 实现api模块中定义的服务接口
    	2. 发布gRPC服务 (创建服务端程序)
    3. xxx-client模块
    	1. 创建服务端stub(代理)
    	2. 基于代理(stub)进行RPC调用
    
  • api 模块编程内容

    1. .proto文件书写protobuf的IDL
    2. protoc命令 把proto文件中的IDL转成成为编程语言
    	protoc --java_out=/xxx/xxx /xxx/xxx/xx  // --java_out 代表生成对应的java代码文件 生成go代码就是 --go
    3. 在实战过程中,我们会使用maven的插件进行protobuf文件的编译,并将其放在对应文件位置
    	https://github.com/grpc/grpc-java
    
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty-shaded</artifactId>
      <version>1.54.1</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-protobuf</artifactId>
      <version>1.54.1</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.54.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>
    
    <!-- 配置插件 -->
    <build>
      <extensions>
        <extension>
          <groupId>kr.motd.maven</groupId>
          <artifactId>os-maven-plugin</artifactId>
          <version>1.7.1</version>
        </extension>
      </extensions>
      <plugins>
        <plugin>
          <groupId>org.xolstice.maven.plugins</groupId>
          <artifactId>protobuf-maven-plugin</artifactId>
          <version>0.6.1</version>
          <configuration>
            <!--生成message信息-->
            <!--os.detected.classifier maven 自定义环境变量,用来获取相应的操作系统信息 -->
            <protocArtifact>com.google.protobuf:protoc:3.21.7:exe:${os.detected.classifier}</protocArtifact>
            <pluginId>grpc-java</pluginId>
            <!--生成service 服务接口-->
            <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.1:exe:${os.detected.classifier}</pluginArtifact>
          </configuration>
          <executions>
            <execution>
              <goals>
                <goal>compile</goal>
                <goal>compile-custom</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
    

    此时执行maven插件的命令 complie生成消息文件,使用complie-custom来生成服务接口信息,之后手动将生成在target文件中的文件移动到main,java包中去

    在生产角度来说,此操作过于繁杂,需要执行两个maven命令,之后手动移动文件夹。如果文件太多,操作麻烦

    此时可以手动创建一个 goal 来执行两个命令,简化maven执行命令次数。

    选择来自plugin goal的两个命令执行一个maven命令即可完成。

    设置maven的输出内容来完成手动移动目录的操作

    <!--设置输出文件目录-->
    <outputDirectory>${basedir}/src/main/java</outputDirectory>
    <!--追加生成,不覆盖删除之前的代码-->
    <clearOutputDirectory>false</clearOutputDirectory>
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L6vF8Ho6-1683617948945)(D:\information\Typora笔记\学习笔记\grpc框架\GRPC - JAVA笔记.assets\image-20230430200633728.png)]

  • xxx-server 服务端模块的开发

    1. 实现业务接口 添加具体的功能 (MyBatis + MysSQL)

      	@Override
      	public void hello(HelloProto.HelloRequest request, StreamObserver<HelloProto.HelloResponse> responseObserver) {
      		// 1. 接受 client 的参数
      		String name = request.getName();
      
      		// 2. 业务处理
      		System.out.println("name parameter:" + name);
      
      		// 3. 封装相应
      		// 3.1 创建响应对象的构造者
      		HelloProto.HelloResponse.Builder builder = HelloProto.HelloResponse.newBuilder();
      		// 3.2 填充数据
      		builder.setResult("hello method invoke ok");
      		// 3.3 封装响应
      		HelloProto.HelloResponse helloResponse = builder.build();
      
      		responseObserver.onNext(helloResponse);
      		responseObserver.onCompleted();
      	}
      
    2. 创建服务端 (Netty)

      public class GRPCServer1 {
      
      	public static void main(String[] args) throws InterruptedException, IOException {
      
      		// 解决端口和服务发布的问题
      		// 绑定端口
      		ServerBuilder<?> serverBuilder = ServerBuilder.forPort(9000);
      		// 发布服务
      		serverBuilder.addService(new HelloServiceImpl());
      		// 创建服务对象
      		Server server = serverBuilder.build();
      
      		server.start();
      		server.awaitTermination();
      		
      	}
      
      }
      
    3. 启动服务,测试效果

      为了更方便的查看日志信息,可以将slf4j引入项目中

      	<dependency>
      		<groupId>org.slf4j</groupId>
      		<artifactId>slf4j-api</artifactId>
      		<version>2.0.7</version>
      	</dependency>
      	<dependency>
      		<groupId>ch.qos.logback</groupId>
      		<artifactId>logback-classic</artifactId>
      		<version>1.4.6</version>
      	</dependency>
      
  • xxx-client 模块

    /client 通过代理对象完成远端对象的调用
    public class GrpcClient1 {
    
    	public static void main(String[] args) {
    
    		// 1. 创建通信的管道
    		ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 9000)
    				.usePlaintext().build();
    
    		// 2. 获得代理对象 stub
    		HelloServiceGrpc.HelloServiceBlockingStub helloService = HelloServiceGrpc.newBlockingStub(managedChannel);
    
    		// 3. 完成rpc调用
    		// 3.1 准备参数
    		HelloProto.HelloRequest.Builder builder = HelloProto.HelloRequest.newBuilder();
    		builder.setName("yuluo");
    		HelloProto.HelloRequest helloRequest = builder.build();
    		// 3.2 进行rpc功能调用
    		HelloProto.HelloResponse helloResponse = helloService.hello(helloRequest);
    		// 获取响应内容
    		String result = helloResponse.getResult();
    		System.out.println("result: " + result);
    
    	}
    
    }
    
  • 开发注意事项

    服务端 处理返回值时
    responseObserver.onNext(helloResponse);  // 通过这个方法,把响应的消息回传给 client
    responseObserver.onCompleted();			 // 通知 client 整个服务结束。底层返回标记
    										 // client 就会监听标记 grpc 自己做的
    										 
    										 
    

gRPC的四种通信方式

  1. 四种通信方式

    1, 简单rpc、一元rpc(Unary RPC)
    2. 服务端流式RPC (Server Streaming RPC)
    3. 客户端流式RPC (Client Streaming RPC)
    4. 双向流RPC (Bi-directinal Stream RPC)
    
  2. 简单RPC(一元RPC)

    1. 特点:

      • 当client发起调用后,提交数据,并且等待 服务端响应

      • 开发过程中,主要采用的是一元RPC的通信方式

      • 语法

        // 服务接口定义
        service HelloService{
        
          rpc hello(HelloRequest) returns (HelloResponse) {}
        
          // 练习
          rpc hello1(HelloRequest1) returns (HelloResponse1) {}
        }
        
  3. 服务端流式RPC

    一个请求对象,服务端可以返回多个结果对象
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-htIDkLxT-1683617948946)(D:\information\Typora笔记\学习笔记\grpc框架\GRPC - JAVA笔记.assets\image-20230501110348866.png)]

    • 使用场景

      client - server
      股票 每时每刻都要发送 价值数据
      
    • 语法

      // 服务接口定义
      service HelloService{
      
        rpc hello(HelloRequest) returns (stream HelloResponse) {}  // 服务端流式 RPC
      
        // 练习
        rpc hello1(HelloRequest1) returns (HelloResponse1) {}  	 // 一元RPC
      }
      
  4. 客户端流式RPC

    指的是客户端发送多个请求对象,服务端只返回一个结果
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OU2874Sf-1683617948946)(D:\information\Typora笔记\学习笔记\grpc框架\GRPC - JAVA笔记.assets\image-20230501160524382.png)]

    • 应用场景

      IOT 物联网【传感器】中应用较多
      client   ->    server
      传感器         服务端     例如车上的传感器每次都发送位置信息到服务端
      
    • 语法

      // 服务接口定义
      service HelloService{
        // 服务端流式RPC
        rpc c2ss(HelloRequest) returns (stream HelloResponse) {}
        // 客户端流式RPC
        rpc cs2s(stream HelloRequest) returns (HelloResponse) {}
      }
      
    • 开发

      1. api
          编写 idl rpc 定义
      2. server
      /**
      	 * 客户端流式RPC
      	 * @param responseObserver
      	 * @return StreamObserver
      	 */
      	@Override
      	public StreamObserver<HelloProto.HelloRequest> cs2s(StreamObserver<HelloProto.HelloResponse> responseObserver) {
      
      		// 监听客户端请求
      		return new StreamObserver<HelloProto.HelloRequest>() {
      			@Override
      			public void onNext(HelloProto.HelloRequest helloRequest) {
      				System.out.println("接收到了客户端发送的一条消息:" + helloRequest.getName());
      			}
      
      			@Override
      			public void onError(Throwable throwable) {
      
      			}
      
      			@Override
      			public void onCompleted() {
      				System.out.println("client 的所有消息都发送到了服务端……");
      
      				// 提供响应:响应的目的是当接受了全部client的提交的信息,并处理后,提供响应
      				HelloProto.HelloResponse.Builder builder = HelloProto.HelloResponse.newBuilder();
      				builder.setResult("this is result!");
      				HelloProto.HelloResponse helloResponse = builder.build();
      
      				responseObserver.onNext(helloResponse);
      				responseObserver.onCompleted();
      			}
      		};
      	}  
      3. client
      	public static void main(String[] args) {
      
      		ManagedChannel localhost = ManagedChannelBuilder.forAddress("localhost", 9000).usePlaintext().build();
      
      		try {
      
      			HelloServiceGrpc.HelloServiceStub helloService = HelloServiceGrpc.newStub(localhost);
      
      			// 监控响应处理
      			StreamObserver<HelloProto.HelloRequest> helloRequestStreamObserver = helloService.cs2s(new StreamObserver<HelloProto.HelloResponse>() {
      				@Override
      				public void onNext(HelloProto.HelloResponse helloResponse) {
      					// 监控响应
      					System.out.println("服务端响应数据:" + helloResponse.getResult());
      				}
      
      				@Override
      				public void onError(Throwable throwable) {
      
      				}
      
      				@Override
      				public void onCompleted() {
      					System.out.println("服务端响应结束……");
      				}
      			});
      
      			// 做请求处理 客户端发送数据到服务端 不定时发送
      			for (int i = 0; i < 10; i++) {
      				HelloProto.HelloRequest.Builder builder = HelloProto.HelloRequest.newBuilder();
      				builder.setName("yuluo" + i);
      				HelloProto.HelloRequest helloRequest = builder.build();
      
      				helloRequestStreamObserver.onNext(helloRequest);
      
      				// 间隔一秒
      				Thread.sleep(1000);
      			}
      
      			// 当所有的消息全部发送给服务端时,告知服务端
      			helloRequestStreamObserver.onCompleted();
      
      			// 设置客户端等待
      			localhost.awaitTermination(12, TimeUnit.SECONDS);
      
      		} catch (Exception e) {
      			e.printStackTrace();
      		} finally {
      			localhost.shutdown();
      		}
      
      	}    
      
  5. 双向流式RPC

    客户端可以发送多个请求消息,服务可以发送多个响应消息
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AnZT5X4M-1683617948947)(D:\information\Typora笔记\学习笔记\grpc框架\GRPC - JAVA笔记.assets\image-20230502150629951.png)]

    • 应用场景:

      聊天室
      
    • 编码

      api
      service HelloService{    
        // 双向流式RPC
        rpc cs2ss(stream HelloRequest) returns (stream HelloResponse) {}
      
      }    
      
      server
      /**
      	 * 双向流式RPC开发
      	 * @param responseObserver
      	 * @return
      	 */
      	@Override
      	public StreamObserver<HelloProto.HelloRequest> cs2ss(StreamObserver<HelloProto.HelloResponse> responseObserver) {
      
      		// 处理客户端请求
      		return new StreamObserver<HelloProto.HelloRequest>() {
      			@Override
      			public void onNext(HelloProto.HelloRequest helloRequest) {
      				System.out.println("服务端接受到客户端提交的信息:" + helloRequest.getName());
      
      				// 处理服务端响应
      				responseObserver.onNext(HelloProto.HelloResponse.newBuilder().setResult("response " + helloRequest.getName() + " result!").build());
      
      			}
      
      			@Override
      			public void onError(Throwable throwable) {
      
      			}
      
      			@Override
      			public void onCompleted() {
      				System.out.println("接收完成所有的客户端消息");
      
      				responseObserver.onCompleted();
      			}
      		};
      	}
          
      client  
          public static void main(String[] args) {
      
      		ManagedChannel localhost = ManagedChannelBuilder.forAddress("localhost", 9000).usePlaintext().build();
      
      		try {
      
      			HelloServiceGrpc.HelloServiceStub helloService = HelloServiceGrpc.newStub(localhost);
      
      			StreamObserver<HelloProto.HelloRequest> helloRequestStreamObserver = helloService.cs2ss(new StreamObserver<HelloProto.HelloResponse>() {
      				@Override
      				public void onNext(HelloProto.HelloResponse helloResponse) {
      					System.out.println("服务端响应的结果" + helloResponse.getResult());
      				}
      
      				@Override
      				public void onError(Throwable throwable) {
      
      				}
      
      				@Override
      				public void onCompleted() {
      					System.out.println("服务端所有响应完成");
      				}
      			});
      
      			for (int i = 0; i < 10; i++) {
      				helloRequestStreamObserver.onNext(HelloProto.HelloRequest.newBuilder().setName("yuluo" + i).build());
      			}
      
      			helloRequestStreamObserver.onCompleted();
      
      			localhost.awaitTermination(12, TimeUnit.SECONDS);
      
      		} catch (Exception e) {
      			e.printStackTrace();
      		} finally {
      			localhost.shutdown();
      		}
      
      	}
      

GRPC 代理方式

1. BlockingStub (常用)
	阻塞,通信方式
2. Stub (常用)
	异步,通过监听处理
3. FutureStub
	同步,异步,类似 NettyFuture
	1. FutureStub 只能应用在一元 RPC
	2. 
public class GrpcClient7 {

   public static void main(String[] args) {

      ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 9000).usePlaintext().build();

      try {

         TestServiceGrpc.TestServiceFutureStub testServiceFutureStub = TestServiceGrpc.newFutureStub(managedChannel);
         ListenableFuture<TestProto.TestResponse> responseListenableFuture = testServiceFutureStub.testYuluo(
               TestProto.TestRequest.newBuilder()
               .setName("yuluo").build());

         /* 同步操作
         TestProto.TestResponse testResponse = responseListenableFuture.get();
         System.out.println(testResponse.getResult());*/

         // 异步操作
         /* 不能和在实战中使用
         responseListenableFuture.addListener(() -> {
            System.out.println("异步的RPC响应回来了……");
         }, Executors.newCachedThreadPool());*/

         // 实战使用代码
         Futures.addCallback(responseListenableFuture, new FutureCallback<TestProto.TestResponse>() {
            @Override
            public void onSuccess(TestProto.TestResponse testResponse) {
               System.out.println("result.getResult() = " + testResponse.getResult());
            }

            @Override
            public void onFailure(Throwable throwable) {

            }
         }, Executors.newCachedThreadPool());

         System.out.println("后续的操作……");

         // 避免异步操作执行太快,睡一会在执行
         managedChannel.awaitTermination(12, TimeUnit.SECONDS);

      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         managedChannel.shutdown();
      }

   }

}

gRPC与Spring Boot整合

版本使用,需要注意:目前不支持spring boot3.0.x版本,使用2.7.6正常

gRP和Spring Boot整合的思想

1. grpc-client
2. grpc-server

Spring Boot与GRPC整合的过程中对于服务端封装

  • 搭建开发环境

    1. 搭建Spring Boot的开发环境
    2. 引入与GRPC相关的内容
    
  • 开发环境

    // 引入服务端依赖
    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-server-spring-boot-starter</artifactId>
        <version>2.14.0.RELEASE</version>
    </dependency>
    
    // 服务接口开发
    @GrpcService
    public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
    
    	@Override
    	public void hello(HelloProto.HelloRequest request, StreamObserver<HelloProto.HelloResponse> responseObserver) {
    		String name = request.getName();
    
    		System.out.println("name is" + name);
    
    		responseObserver.onNext(HelloProto.HelloResponse.newBuilder().setResult("this is result").build());
    		responseObserver.onCompleted();
    	}
    
    }
    
    # 核心配置内容  grpc的端口号
    spring:
      application:
        # 在项目中必须显式声明应用名,没有默认值
        name: boot-server
    
      # 不启动tomcat服务器,使用的是grpc的服务端
    #  main:
    #    web-application-type: none
    
    grpc:
      server:
        port: 9000
    
    // 引入客户端依赖
    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-client-spring-boot-starter</artifactId>
        <version>2.14.0.RELEASE</version>
    </dependency>
        
    // client开发
    @RestController
    public class TestController {
    
    	@GrpcClient("grpc-server")
    	private HelloServiceGrpc.HelloServiceBlockingStub stub;
    
    	@GetMapping("/test")
    	public String test1(String name) {
    		System.out.println("name = " + name);
    
    		HelloProto.HelloResponse helloResponse = stub.hello(HelloProto.HelloRequest.newBuilder().setName(name).build());
    
    		return helloResponse.getResult();
    	}
    
    }
       
    // 配置
    server:
      port: 8081
    
    spring:
      application:
        name: boot-client
    
    grpc:
      client:
        grpc-server:
          address: 'static://localhost:9000'
          negotiation-type: plaintext
    

gRPC 的高级应用

1. 拦截器 一元拦截器
2. Stream Tracer 【监听流】 流拦截器
3. Retry Policy 客户端重试
4. NameResolver   注册中心
5. 负载均衡
6. GRPC与微服务整合
	- 序列化 protobuf与dubbo
	- grpc 与 Gateway
	- grpc 与 JWT
	- grpc 与 Nacos2.0
	- grpc 可以替换 OpenFeign

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/19341.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VS2022编译libiconv-1.17

需求概述 获得最新版本的windows下可用的libiconv静态库。 解决方案 概述 使用VS2022编译libiconv-1.17。需要对源码手动进行配置。 本文所述的方法同样适用于动态库&#xff0c;并且理论上适用于VS2010~2022所有版本。 如果你不在乎libiconv的版本&#xff0c;可以参考 …

Redis缓存

就先不连接数据库了 我们测试缓存 实体类&#xff1a; Data AllArgsConstructor NoArgsConstructor public class User implements Serializable {private int id;private String name;private String sex;private String addr; } service&#xff1a; Service public…

小家电LED显示驱动多功能语音芯片IC方案 WT2003H4 B002

随着时代的进步&#xff0c;智能家电的普及已经成为了一个趋势。而在智能家电中&#xff0c;LED显示屏也成为了不可或缺的一部分。因此&#xff0c;在小家电的设计中&#xff0c;LED显示驱动芯片的应用也越来越广泛。比如&#xff1a;电饭煲、电磁炉、数字时钟、咖啡机、电磁炉…

java版spring cloud 企业电子招投标采购系统源码之首页设计

随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以及审计监督要…

“正大杯”第十三届市场调查与分析大赛[省一]经验总结+复盘

目录 1 前期组队 2 队员组成 队长-成员1 应用统计学专业 成员2 化学实验专业 成员3-本人 物联网工程专业 成员4 金融ACCA专业 成员5 应用物理学 总结 3 比赛进度 3月中旬 部分图表的制作 问卷设计与制作 稍微改动主题 问卷相关总结 前期调查部分论文框架 3月…

怎么把webp文件转换为jpg?这几种方法值得学习!

怎么把webp文件转换为jpg&#xff0c;我想这样的问题对于那些和图片打交道不多的人来说确实有些困难吧。在我们要处理这个问题之前&#xff0c;我们先来了解一下图片格式webp吧。要是知道Youtube、Gmail、Google Play 中都可以看到 WebP 的身影&#xff0c;而 Chrome 网上商店甚…

高阶python | 堆栈列表:RPN应用(模拟逆波兰式功能实现)

python版本&#xff1a;3.10 在列表中&#xff0c;append和pop方法有一个特殊的用途。可以在列表上使用这两个方法让列表变成一个堆栈使用。 这就是一个栈&#xff0c;它是先进后出&#xff0c;类似单门轿厢电梯一样的设计&#xff0c;出入口共用 堆栈最有用的应用之一就是做逆…

如何解决请求参数为JSON时,采用IO流读取,只能请求一次的问题?

如何解决请求参数为JSON时&#xff0c;采用IO流读取&#xff0c;只能请求一次的问题&#xff1f; 一、错误演示1. 创建项目&#xff0c;添加所需依赖2. 配置redis环境3. 写一个简单的测试请求4. 写一个拦截器&#xff0c;拦截请求5. WebConfig 注册拦截器6. 测试请求 二、问题解…

VR全景园区:数字化旅游业的新未来

VR全景园区是未来数字化旅游业的一种新兴形式。它利用高清晰度的3D图像和360度全景拍摄技术&#xff0c;将景区中的自然风光、历史文化和人文风情等元素呈现在游客面前。VR全景园区不仅可以为游客提供身临其境的参观体验&#xff0c;还可以有效地推广当地的文化和旅游资源。 【…

调试和优化遗留代码

1. 认识调试器 1.1 含义 一个能让程序运行、暂停、然后对进程的状态进行观测甚至修改的工具。 在日常的开发当中使用非常广泛。(PHP开发者以及前端开发者除外) 1.2 常见的调试器 Go语言的自带的 delve 简写为 “dlv”GNU组织提供的 gdbPHP Xdebug前端浏览器debug 调试 1.3…

English Learning - L3 作业打卡 Lesson2 Day8 2023.5.12 周五

English Learning - L3 作业打卡 Lesson2 Day8 2023.5.12 周五 引言&#x1f349;句1: The color green is natural for trees and grass.成分划分弱读语调 &#x1f349;句2: But it is an unnatural color for humans.成分划分弱读连读语调 &#x1f349;句3: A person who h…

1.SpringBoot基础篇

SpringBoot 文档更新日志 版本更新日期操作描述v1.02021/11/14A基础篇 前言 ​ 很荣幸有机会能以这样的形式和互联网上的各位小伙伴一起学习交流技术课程&#xff0c;这次给大家带来的是Spring家族中比较重要的一门技术课程——SpringBoot。一句话介绍这个技术&#xff0c;…

自学软件测试,从10K到40K的技术路线,也就是这些东西...

如果有一天我从梦中醒来时&#xff0c;发现自己的几年自动化测试工程师经验被抹掉&#xff0c;重新回到了一个小白的状态。我想要重新自学自动化测试&#xff0c;然后找到一份自己满意的测试工作&#xff0c;我想大概只需要6个月的时间就够了&#xff0c;如果比较顺利的话&…

头部企业走入无人区,国产数智化厂商挑大梁

本文转自数智前线 文&#xff5c;石兆 编&#xff5c;游勇 央国企数智化与信创化双重需求叠加&#xff0c;国产厂商挑大梁&#xff0c;助力企业升级数智化底座&#xff0c;实现价值化国产替代。 4月&#xff0c;在北京用友产业园的数智剧院里&#xff0c;近千位来自30个行业…

uniapp实现微信小程序横屏适配问题demo效果(整理)

使用VMIN进行布局 先了解css3的两个属性vmax和vmin vmax 相对于视口的宽度或高度中较大的那个。其中最大的那个被均分为100单位的vmax vmin 相对于视口的宽度或高度中较小的那个。其中最小的那个被均分为100单位的vmin竖屏布局的时候&#xff0c;750rpx就是竖屏布局屏幕的宽度…

Golang每日一练(leetDay0062) BST迭代器、地下城游戏

目录 173. 二叉搜索树迭代器 Binary Search Tree Iterator &#x1f31f;&#x1f31f; 174. 地下城游戏 Dungeon Game &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 …

ASEMI代理LT8609AJDDM#WTRPBF原装ADI车规级芯片

编辑&#xff1a;ll ASEMI代理LT8609AJDDM#WTRPBF原装ADI车规级芯片 型号&#xff1a;LT8609AJDDM#WTRPBF 品牌&#xff1a;ADI /亚德诺 封装&#xff1a;DFN-10 批号&#xff1a;2023 安装类型&#xff1a;表面贴装型 引脚数量&#xff1a;10 工作温度:-40C~125C 类型…

python基础语法

一、配置python环境 &#xff08;1&#xff09;设置环境变量 path添加 C:\Program Files\Python3_11 C:\Program Files\Python3_11\Scripts &#xff08;2&#xff09;了解pip 什么是pip&#xff1f; pip是pyton包管理器&#xff0c;pypi&#xff08;Python Package Ind…

前端开发之Echarts 图表渐变两种实现方式和动态改变图表类型

前端开发之Echarts 图表渐变两种实现方式 前言效果图一、echarts中存在两种渐变方式1、color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{}&#xff0c;{}&#xff0c;{}])简单案例 2、{type: linear,x: 0,y: 0,x2: 0,y2: 1, [{}&#xff0c;{}&#xff0c;{}]}案例 二…

Codeforces Round 872 (Div. 2)

Problem - D2 - Codeforces 思路&#xff1a; 我们设good点到所有k点的距离和为dis。 假设good点不止一个&#xff0c;那么我们good点的dis应该都是相等的&#xff08;废话&#xff09;。设当前点u是good点&#xff0c;如果他往儿子v移动&#xff0c;儿子有w个点属于k&#…