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

devtools/2025/1/18 14:23:05/

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

1、RestTemplate

java">	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");              // #2httpHeaders.add("Content-Type", "application/protobuf");    // #3httpHeaders.add("Accept", "application/protobuf");          // #4HttpEntity<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

java">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")));@Overridepublic List<MediaType> getWritableMediaTypes() {return MEDIA_TYPES;}@Overridepublic boolean canWrite(ResolvableType elementType, MediaType mediaType) {return true;}@Overridepublic 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);}
}
java">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")));@Overridepublic List<MediaType> getReadableMediaTypes() {return MEDIA_TYPES;}@Overridepublic boolean canRead(ResolvableType elementType, MediaType mediaType) {return true;}@Overridepublic Flux<Object> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints) {Mono<Object> mono = createObject(message);return mono.flux();}@Overridepublic 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;}
}
java">	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.ppmy.cn/devtools/151579.html

相关文章

PHP:写接口与接口的调用(完整版,封装公共方法)

说明&#xff1a;绑定的资源详细展示了两个项目的接口、接口调用的实现&#xff0c;已经数据库的连接&#xff0c;目录展示更加一目了然&#xff0c;有需要可以下载资源&#xff0c;实际文章已经描述的很详细了 一、A页面-发送请求页面 1、说明 发送请求部分&#xff0c;去调…

如何将原来使用cmakelist编译的qt工程转换为可使用Visual Studio编译的项目

将原来使用CMakeLists.txt编译的Qt工程转换为可使用Visual Studio编译的项目&#xff0c;可以通过以下步骤实现&#xff1a; 一、准备阶段 安装必要的软件&#xff1a; 确保已安装Visual Studio&#xff0c;并选择了C开发相关的组件。安装CMake&#xff0c;并确保其版本与Qt和…

初学者如何用 Python 写第一个爬虫?

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

.NET MAUI进行UDP通信

.NET MAUI是一个开源的跨平台框架库。NET&#xff0c;使创建丰富、现代的用户界面变得容易,.NET MAUI提供了一个多平台应用程序UI。我们可以使用.NET MAUI&#xff0c;用于使用C#和XAML创建本地移动和桌面应用程序。它还支持XAML热重载&#xff0c;这意味着我们可以在运行时编辑…

赛灵思(Xilinx)公司Artix-7系列FPGA

苦难从不值得歌颂&#xff0c;在苦难中萃取的坚韧才值得珍视&#xff1b; 痛苦同样不必美化&#xff0c;从痛苦中开掘出希望才是壮举。 没有人是绝对意义的主角&#xff0c; 但每个人又都是自己生活剧本里的英雄。滑雪&#xff0c;是姿态优雅的“贴地飞行”&#xff0c;也有着成…

使用 ChatGPT 生成和改进你的论文

文章目录 零、前言一、操作引导二、 生成段落或文章片段三、重写段落四、扩展内容五、生成大纲内容六、提高清晰度和精准度七、解决特定的写作挑战八、感受 零、前言 我是虚竹哥&#xff0c;目标是带十万人玩转ChatGPT。 ChatGPT 是一个非常有用的工具&#xff0c;可以帮助你…

QT开发技术 【基于TinyXml2的对类进行序列化和反序列化】 二

一、对上一篇进行优化和进一步完善 二、增加序列化器类 需要序列化的类继承该类进行操作 class CXmlSerializer { public:CXmlSerializer() default;virtual ~CXmlSerializer() default;bool Serialize(std::string& strXml);bool Deserialize(const std::string&…

如何攻击一个服务器(仅用于教育及娱乐实验目的)

import socket import osdef create_virus():# 创建一个简单的病毒脚本&#xff0c;它会不断尝试连接目标服务器并发送恶意数据virus_code """ import socket import time import threadingdef attack_server(ip, port):while True:try:s socket.socket(socke…