SpringBoot:使用HTTP2+protobuf实现高性能微服务调用(二)客户端实现

news2025/1/17 4:57:36

      上一篇文章中已经介绍了服务器端如何改造以支持HTTP2.0 + protobuf,并且给了一个客户端实现的例子,但这个例子并没有与SpringBoot结合。比如能否让RestTemplate或WebClient支持HTTP2.0 + protobuf,下面就给出代码:

1、RestTemplate

	public static void doWithRestTemplate(ReqtObj reqt) {
		String url = "http://127.0.0.1:8080/object/doTest";

		RestTemplate restTemplate = new RestTemplate();
		restTemplate.getMessageConverters().add(new ProtoBufHttpMessageConverter());

		HttpHeaders httpHeaders = new HttpHeaders();
//		httpHeaders.add("Content-Type", "application/json");        // #1
//		httpHeaders.add("Accept", "application/json");              // #2
		httpHeaders.add("Content-Type", "application/protobuf");    // #3
		httpHeaders.add("Accept", "application/protobuf");          // #4

		HttpEntity<ReqtObj> httpEntity = new HttpEntity<>(reqt, httpHeaders);

		ResponseEntity<RespObj> respEntity = restTemplate.exchange(url,
				HttpMethod.POST, httpEntity, RespObj.class);

		RespObj reqtObj = respEntity.getBody();

		System.out.println("++++++++++++++++++++" + reqtObj.toString());
	}

上面的代码使RestTemplate能够支持protobuf格式的报文,但由于RestTemplate先天的局限性,只能支持HTTP/1.1,不能支持HTTP/2.0。

另外,将#3#4注释掉后,上面的代码就可以直接变回采用JSON报文了。

2、WebClient

package com.cebbank;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.reactivestreams.Publisher;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.HttpMessageWriter;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class ProtoBufMessageWriter implements HttpMessageWriter<Object> {

	private static final List<MediaType> MEDIA_TYPES = Collections
			.unmodifiableList(Arrays.asList(new MediaType("application", "protobuf")));

	@Override
	public List<MediaType> getWritableMediaTypes() {
		return MEDIA_TYPES;
	}

	@Override
	public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
		return true;
	}

	@Override
	public Mono<Void> write(Publisher<? extends Object> inputStream, ResolvableType elementType, MediaType mediaType,
			ReactiveHttpOutputMessage message, Map<String, Object> hints) {

		Flux<DataBuffer> dataBufferFlux = Flux.from(inputStream).map(value -> {
			byte[] data = ProtoBufTools.serialize(value);

			DataBufferFactory bufferFactory = message.bufferFactory();
			DataBuffer buffer = bufferFactory.allocateBuffer(data.length);
			buffer.write(data);

			return buffer;
		});
		return message.writeWith(dataBufferFlux);
	}
}
package com.cebbank;

import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.codec.HttpMessageReader;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class ProtoBufMessageReader implements HttpMessageReader<Object> {

	private static final List<MediaType> MEDIA_TYPES = Collections
			.unmodifiableList(Arrays.asList(new MediaType("application", "protobuf")));

	@Override
	public List<MediaType> getReadableMediaTypes() {
		return MEDIA_TYPES;
	}

	@Override
	public boolean canRead(ResolvableType elementType, MediaType mediaType) {
		return true;
	}

	@Override
	public Flux<Object> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints) {
		Mono<Object> mono = createObject(message);

		return mono.flux();
	}

	@Override
	public Mono<Object> readMono(ResolvableType elementType, ReactiveHttpInputMessage message,
			Map<String, Object> hints) {
		Mono<Object> mono = createObject(message);

		return mono;
	}

	private Mono<Object> createObject(ReactiveHttpInputMessage message) {
		Mono<Object> mono = message.getBody().collectList().map(list -> {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();

			try {
				for (DataBuffer dataBuffer : list) {
					int len = dataBuffer.readableByteCount();
					byte[] buffer = new byte[len];
					dataBuffer.read(buffer);

					bos.write(buffer);
				}

				byte[] data = bos.toByteArray();

				return ProtoBufTools.deserialize(data, RespObj.class);
			} catch (Exception e) {
				e.printStackTrace();
			}

			return null;
		});

		return mono;
	}
}
	public static void doWithWebClientUseReactor(ReqtObj reqt) {
		String url = "http://127.0.0.1:8080/object/doTest";

		try {
			HttpClient httpClient = HttpClient.create().protocol(HttpProtocol.H2C);
			ReactorClientHttpConnector reactorClientHttpConnector = new ReactorClientHttpConnector(httpClient);

			WebClient webClient = WebClient.builder()//
					.clientConnector(reactorClientHttpConnector)//
					.codecs(configurer -> {

						configurer.customCodecs().register(new ProtoBufMessageReader());
						configurer.customCodecs().register(new ProtoBufMessageWriter());
					})//
					.build();

			System.out.println("======================" + reqt.toString());
			System.out.println("reqtLen=" + data.length);

			MediaType mediaType = new MediaType("application", "protobuf");
//			MediaType mediaType = new MediaType("application", "json");

			Mono<RespObj> RespObjMono = webClient.post().uri(url).contentType(mediaType).accept(mediaType)
					.bodyValue(reqt).retrieve().bodyToMono(RespObj.class);

			RespObj resp = RespObjMono.block();
			System.out.println("======================" + resp.toString());

		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

通过实现ProtoBufMessageReader和ProtoBufMessageWriter,就可以让WebClient支持HTTP2.0 + protobuf了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s物料清单工具——KubeClarity

介绍 KubeClarity是一个用于检测和管理容器镜像和文件系统的软件清单&#xff08;SBOM&#xff09;和漏洞的工具。它扫描运行时的K8s集群和CI/CD流水线&#xff0c;以增强软件供应链安全性。 安装 添加 helm 仓库 helm repo add kubeclarity https://openclarity.github.io…

citrix netscaler13.1 重写负载均衡响应头(基础版)

在 Citrix NetScaler 13.1 中&#xff0c;Rewrite Actions 用于对负载均衡响应进行修改&#xff0c;包括替换、删除和插入 HTTP 响应头。这些操作可以通过自定义策略来完成&#xff0c;帮助你根据需求调整请求内容。以下是三种常见的操作&#xff1a; 1. Replace (替换响应头)…

Linux Centos 安装Jenkins到服务

一、前言 假设你已经下载了jenkins.war 安装了对应的jdk&#xff0c;下面我们来安装jenkins&#xff0c;以服务的形式安装。 二、安装 1&#xff09;将jenkins.war拷贝到合适的位置&#xff0c;我的位置 /u01/jenkins/ &#xff0c;位置你自己选。 2&#xff09;创建系统用户…

网安——计算机网络基础

一、计算机网络概述 1、Internet网相关概念及发展 网络&#xff08;Network&#xff09;有若干结点&#xff08;Node&#xff09;和连接这些结点的链路&#xff08;link&#xff09;所组成&#xff0c;在网络中的结点可以是计算机、集线器、交换机或路由器等多个网络还可以通…

Xcode 正则表达式实现查找替换

在软件开发过程中&#xff0c;查找和替换文本是一项常见的任务。正则表达式&#xff08;Regular Expressions&#xff09;是一种强大的工具&#xff0c;可以帮助我们在复杂的文本中进行精确的匹配和替换。Xcode 作为一款流行的开发工具&#xff0c;提供了对正则表达式的支持。本…

数据结构9——二叉搜索树

&#x1f947;1.二叉搜索树的概念 二叉搜索树(Binary Search Tree,BST)又称二叉排序树或二叉查找树&#xff0c;其要么是一棵空树&#xff0c;要么具有以下性质&#xff1a; ①&#xff1a;左子树上所有节点的值都小于根节点&#xff1b; ②&#xff1a;右子树上所有节点的值都…

leetcode刷题记录(四十八)——128. 最长连续序列

&#xff08;一&#xff09;问题描述 128. 最长连续序列 - 力扣&#xff08;LeetCode&#xff09;128. 最长连续序列 - 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。请你设计并实现时间复…

c语言——【linux】多进程编程 【进程的创建,相关shell指令,进程状态切换,回收资源,守护进程等】

1.思维导图 2.进程的创建 函数原型&#xff1a;pid_t fork(void); 功能描述&#xff1a;以当前进程为父进程&#xff0c;创建一个子进程 进程链和进程扇的创建 3.多进程具体使用 3.1进程替换 exec 函数一族 int execl(const char *path, const char *arg, ... /* (char *) N…

在服务器上增加新网段IP的路由配置

在服务器上增加新网段IP的路由配置 前提条件步骤一:检查当前路由表步骤二:添加新路由步骤三:验证新路由步骤四:持久化路由配置脚本示例结论在网络管理中,路由配置是一项基本且重要的任务。它决定了数据包在网络中的传输路径。本文将详细介绍如何在服务器上增加新的路由配置…

国产fpga nvme ip高速存储方案设计

国产高速存储方案主要是使用nvme ip实现高速存储方案&#xff0c;nvme ip采用纯verilog语言实现&#xff0c;用户拿到nvme ip使用起来也很简单。 先看看效果如 zu7eg板子&#xff0c;这个芯片支持pcie3.0 x4. zynq 7045板子只支持pcie 2.0 x4 速度测试&#xff0c;测试nvme …

浅谈云计算14 | 云存储技术

云存储技术 一、云计算网络存储技术基础1.1 网络存储的基本概念1.2云存储系统结构模型1.1.1 存储层1.1.2 基础管理层1.1.3 应用接口层1.1.4 访问层 1.2 网络存储技术分类 二、云计算网络存储技术特点2.1 超大规模与高可扩展性2.1.1 存储规模优势2.1.2 动态扩展机制 2.2 高可用性…

[操作系统] 深入理解约翰·冯·诺伊曼体系

约翰冯诺依曼&#xff08;John von Neumann&#xff0c;1903年12月28日—1957年2月8日&#xff09;&#xff0c;原名诺伊曼亚诺什拉约什&#xff08;Neumann Jnos Lajos&#xff09;&#xff0c;出生于匈牙利的美国籍犹太人数学家&#xff0c;20世纪最重要的数学家之一&#xf…

ElasticSearch上

安装ElasticSearch Lucene&#xff1a;Java语言的搜索引擎类库&#xff0c;易扩展&#xff1b;高性能&#xff08;基于倒排索引&#xff09;Elasticsearch基于Lucene&#xff0c;支持分布式&#xff0c;可水平扩展&#xff1b;提供Restful接口&#xff0c;可被任何语言调用Ela…

Qt应用之MDI(多文档设计)

qt creator 版本6.8.0 MinGW 64bit 由此模块可以扩展成设计一个qt文本编辑器。 界面如下 部分功能展示如下 新建文件 打开文件 mdi模式、级联模式和平铺模式 界面和程序构建过程。 1.如图所需.cpp和.h文件 2.mainwindow.ui和tformdoc.ui界面布局如下 不懂什么是Action如何…

【博主推荐】VUE常见问题及解决方案

文章目录 1.找不到模块“../views/index.vue”或其相应的类型声明。ts(2307)2.当改变 Vue 实例中的数据时&#xff0c;视图没有相应地更新3.在某些复杂的异步操作或者多个数据交互场景下&#xff0c;数据绑定的更新在时间上出现延迟4.父组件无法将数据正确地传递给子组件&#…

【Apache Doris】周FAQ集锦:第 29 期

引言 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目&#xff01; 在这个栏目中&#xff0c;每周将筛选社区反馈的热门问题和话题&#xff0c;重点回答并进行深入探讨。旨在为广大用户和开发者分享有关 Apache Doris 的常见问题。 通过这个每周 FAQ 栏目&#xff0c;希望帮助社…

TensorFlow DAY3: 高阶 API(Keras,Estimator)(完)

TensorFlow 作为深度学习框架&#xff0c;当然是为了帮助我们更便捷地构建神经网络。所以&#xff0c;本次实验将会了解如何使用 TensorFlow 来构建神经网络&#xff0c;并学会 TensorFlow 构建神经网络的重要函数和方法。 知识点 Keras 顺序模型Keras 函数模型Keras 模型存储…

【React】脚手架进阶

目录 暴露webpack配置package.json的变化修改webpack.config.js配置less修改域名、端口号浏览器兼容处理处理跨域 暴露webpack配置 react-scripts对脚手架中的打包命令进行封装&#xff0c;如何暴露这些打包配置呢&#xff1f;上篇写到在package.json中的scripts配置项中有eje…

Thrustmaster Hotas Warthog飞行操作杆开发

目录 0 摘 要 &#xff1a;简单说一下这篇文章在搞啥 1 背 景 &#xff1a;什么需求以及对开发的背景调查 2 环境配置 &#xff1a;具体需要什么环境&#xff0c;对软件层面的需求 3 硬件测试 &#xff1a;测试遥感器…

OpenCV基于均值漂移算法(pyrMeanShiftFiltering)的水彩画特效

1、均值漂移算法原理 pyrMeanShiftFiltering算法结合了均值迁移&#xff08;Mean Shift&#xff09;算法和图像金字塔&#xff08;Image Pyramid&#xff09;的概念&#xff0c;用于图像分割和平滑处理。以下是该算法的详细原理&#xff1a; 1.1 、均值迁移&#xff08;Mean …