RestTemplate配置和使用

news2024/11/26 17:30:42

在项目中,如果要调用第三方的http服务,就需要发起http请求,常用的请求方式:第一种,使用java原生发起http请求,这种方式不需要引入第三方库,但是连接不可复用,如果要实现连接复用,需要自己实现管理,相对来说比较麻烦;第二种就是使用第三方的库,比较常用的就是apache的httpclient和okhttp两个包,他们都对http请求进行了封装并且可以管理连接,对于重复使用的连接会有比较好的性能;第三种就是在springboot中使用RestTemplate进行请求,它是对http请求的封装,默认使用的java原生进行请求,也支持整合httpclient和okhttp库,提供很好的封装和扩展性。下面就介绍一下如何在项目中使用和相关配置:
要在项目中使用RestTemplate,首先需要定义一个Bean将它注入到系统中:

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

这种方式注入的对象默认使用SimpleClientHttpRequestFactory工厂,它使用java原生方式发起http请求,性能并不好,还有一种注入方式是:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

RestTemplateBuilder这种注入方式会根据系统中是否引入第三方的http库来灵活选择httpclient工厂,通过跟踪源码发现,目前支持httpclient和okhttp3两个库,如下图:
判断factory类型
默认支持的两种factory

虽然通过上面的方式注入的RestTemplate会自动选择创建httpclient的工厂,但是该工厂相关参数都是默认配置,有时候并不能满足我们系统的需求,比如要设置读写超时时间,默认的配置中是永远不超时,这样如果请求的第三方系统响应慢会导致整个系统崩溃。
不加任何配置的RestTemplate内容如下:
restTemplate的默认工厂和参数
要调整超时时间,就需要使用下面这种方式注入工厂,并配置相关参数:

@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    factory.setConnectTimeout(3000);
    factory.setReadTimeout(3000);
    return factory;
}

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
    return new RestTemplate(factory);
}

再次查看RestTemplate的内容:
设置参数后的restTemplate
通常情况下我们都不会使用java原生的方式发起http请求,因为每次发起http请求都要重新建立连接,这样会大大降低系统性能,在这个示例中我选择使用apache下的httpclient库扩展,首先需要在项目中引入相关依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.12</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5.12</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.13</version>
</dependency>

注意包的版本要匹配,否则会有报错,接下来就是将httpclient注入到RestTemplate中,这里有两种方式,第一种是使用下面的配置

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

它可以检测到系统中引入了httpclient依赖,会自动将原生的工厂类替换为apacheHttpClient的工厂:
请添加图片描述
但是这种方式使用的配置都是默认的,如连接池大小为20个,超时时间永不超时等。这种配置不能满足我们的需求,这时候就需要根据自己系统的要求调整配置参数了,下面的示例代码是我的一个简单配置:

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.UnsupportedSchemeException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

@Configuration
public class RestTemplateConfig {

    @Bean
    public ClientHttpRequestFactory apacheHttpRequestFactory() {
        // 重试配置
        HttpRequestRetryHandler retryHandler = (e, count, context) -> {
            System.out.println("连接失败次数|" + count);
            e.printStackTrace();

            if (count >= 5) {       // 假设已经重试了5次,就放弃
                return false;
            }
            // 返回true需要重试
            if (e instanceof NoHttpResponseException            // 请求无响应就重试
                    || e instanceof ConnectTimeoutException     // 连接超时
                    || e instanceof SocketException             // 连接异常
                    || e instanceof SocketTimeoutException      // socket超时
            ) {
                try {
                    // 重试时间间隔:1s
                    TimeUnit.MILLISECONDS.sleep(1000);
                } catch (InterruptedException ex) {
                    e.printStackTrace();
                }
                return true;
            }
            // 返回false不需要重试
            if (e instanceof SSLException                       // SSL握手异常不要重试
                    || e instanceof InterruptedIOException      // 中断
                    || e instanceof UnknownHostException        // 目标server不可达
                    || e instanceof UnsupportedSchemeException  // 协议不支持
            ) {
                return false;
            }

            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            // 假设请求是幂等的,就再次尝试
            return !(request instanceof HttpEntityEnclosingRequest);
        };

        Registry<ConnectionSocketFactory> registry = RegistryBuilder
                .<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();

        // 连接池配置
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(registry);
        // 最大连接数
        connManager.setMaxTotal(1000);
        // 每个路由最大连接数
        connManager.setDefaultMaxPerRoute(200);

        // 超时配置:都为5s
        RequestConfig reqConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(5000)      // 从连接池中获取连接超时时间
                .setConnectTimeout(5000)                // 连接建立超时时间,也就是三次握手完成时间
                .setSocketTimeout(5000)                 // 等待服务器响应超时时间
                .build();

        // 构建httpclient
        CloseableHttpClient client = HttpClients.custom()
                .setConnectionManager(connManager)
                .setDefaultRequestConfig(reqConfig)
                .setRetryHandler(retryHandler)
                .build();

        return new HttpComponentsClientHttpRequestFactory(client);
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(apacheHttpRequestFactory());
    }
}

通过上面的配置就将自定义的连接参数注入到RestTemplate中了。在使用的位置,只需要引入restTemplate就可以正常使用了:

@Autowired
private RestTemplate restTemplate;

使用restTemplate发起http请求的方法封装为两种形式:一种是ForObject(),如getForObject()、postForObject(),这种只会返回数据;另一种是ForEntity(),如getForEntity()、postForEntity(),这种方式会返回数据和状态信息。
get请求比较简单,下面主要演示一下post请求中的提交表单数据和json数据的示例:

  1. 提交表单数据:
// 请求地址
String url = "http://localhost:8081/test/add";
// form表单数据
MultiValueMap<String, Object> data = new LinkedMultiValueMap<>();
data.add("name", "james");
data.add("age", 38);
// 请求头部
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 发起请求
ResponseEntity<String> result = restTemplate.postForEntity(url, new HttpEntity<>(data, headers), String.class);
  1. 提交json数据:
// 请求地址
String url = "http://localhost:8081/test/add";
// json数据
String data = "{\"name\":\"james\",\"age\":38}";
// 请求头部
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 发起请求
ResponseEntity<String> result = restTemplate.postForEntity(url, new HttpEntity<>(data, headers), String.class);

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

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

相关文章

武汉凯迪正大—电能质量分析仪功能介绍

功能介绍&#xff1a; 测试功能&#xff1a; 波形实时显示&#xff08;4路电压/4路电流&#xff09;&#xff1b;电压和电流真有效值&#xff1b;电压直流成份&#xff1b;电流和电压峰值&#xff1b;电流和电压一段时间内的最大/最小值&#xff1b;相量图显示&#xff1b;各相…

深入浅出理解ResNet网络模型+PyTorch实现

温故而知新&#xff0c;可以为师矣&#xff01; 一、参考资料 原始论文&#xff1a;Identity Mappings in Deep Residual Networks 原论文地址&#xff1a;Deep Residual Learning for Image Recognition ResNet详解PyTorch实现 PyTorch官方实现ResNet 【pytorch】ResNet18、…

10道高频Vuex面试题快问快答

※其他的快问快答&#xff0c;看这里&#xff01; 10道高频Qiankun微前端面试题快问快答 10道高频webpack面试题快问快答 20道高频CSS面试题快问快答 20道高频JavaScript面试题快问快答 30道高频Vue面试题快问快答 面试中的快问快答 快问快答的情景在面试中非常常见。 在面试过…

凡泰极客亮相香港金融科技周,投身大湾区数字化建设

11月2-3日&#xff0c;作为全球性的金融科技盛会——香港金融科技周2023于香港会展中心隆重开幕。大会云集全球500多家金融机构及金融科技企业参展&#xff0c;吸引超过3万余人次相关人士参会。 凡泰极客作为中国领先的金融科技企业受邀参会&#xff0c;吸引了多领域专家、投资…

php加密解密的用法(对称加密,非对称加密)

加密和摘要的区别 ***摘要&#xff1a;是从已知的数据中&#xff0c;通过摘要计算出一个值&#xff0c;一个数据对应一个或多个摘要的值 *** 比如&#xff1a;md5 和 sha1 sha256 hash 就是得到一个特定的值 &#xff0c;同一个数据得到的md5 是一样的&#xff0c;不会改变的 比…

BeanUtils.copyProperties浅拷贝的坑你得知道?

今天想写一篇文章&#xff0c;主要关于深拷贝和浅拷贝相关的&#xff0c;主要是最近写代码的时候遇到一个BUG&#xff0c;刚好涉及到浅拷贝导致的问题。 问题背景 现在有一个需要是需要修改门店信息&#xff0c;门店也区分父门店和子门店&#xff0c;父门店被编辑更新是需要通过…

数据中台之数据分析

效果界面 技术方案 Notebook集成 在您的数据平台上,创建一个能够与Jupyter Notebook通讯的服务。通过Jupyter Notebook的HTTP API与Notebook实例进行交互,执行代码、获取输出等。用户界面 在数据开发/数据分析的代码框右上方,添加一个机器人样式的图标,用户点击后可以调起…

很多个pdf怎么合并在一起?

很多个pdf怎么合并在一起&#xff1f;作为一个办公室的伙伴&#xff0c;对于PDF格式肯定不会陌生。它强大的功能为我们的工作提供了许多便利。由于PDF文件格式的稳定性和安全性较高&#xff0c;我们通常在工作或学习中使用它来传输文件&#xff0c;很多人都喜欢将办公文件都做成…

linux系统下读取当前硬盘的温度

这个其实很简单&#xff0c;借助于smartctl工具&#xff08;Ubuntu默认安装好了&#xff09;&#xff0c;标红的部分就是当前温度&#xff0c;单位是摄氏度。 sudo smartctl -l scttempsts /dev/sda

自然语言处理中的文本聚类:揭示模式和见解

一、介绍 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;文本聚类是一种基本且通用的技术&#xff0c;在信息检索、推荐系统、内容组织和情感分析等各种应用中发挥着关键作用。文本聚类是将相似文档或文本片段分组为簇或类别的过程。这项技术使我们能够发现隐藏的…

AutoCompleteTextView自动完成文本框

1.AutoCompleteTextView的常用XML属性&#xff1a; andraid:completionHint 用于为弹出的下拉菜单指定提示标题&#xff0c;值为String&#xff1b;可不加。 android:completionThreshold(门槛) 用于指定用户至少输入几个字体才会显示提示&#xff0c;值为int。andraid:dro…

Doc as Code (4):使用Git做版本管理,而不是使用目录做版本管理

▲ 搜索“大龙谈智能内容”关注GongZongHao▲ 在引入版本管理工具之前&#xff0c;文档工程师使用文件系统提供的功能来管理文件。大家是这样工作的&#xff1a; 文件按照分类放在不同的目录里&#xff0c;使用编辑器&#xff08;如&#xff1a;MS Word&#xff09;打开文档进…

SOLIDWORKS --流体仿真篇

SIMULIA流体仿真是什么? 模拟并预测复杂环境下围绕和穿过实体和结构的稳态及瞬态的内外部流(包括热传递)&#xff0c;例如湍流气流、颗粒运动、表面沉积等 .提供定性、定量以及可视化的分析手段,可实现多尺度多物理的视觉效果 SIMULIA流体仿真能做什么? 1.高效的仿真前处理…

多变量线性回归练习

读取数据特征归一化 mean是均值 将特征大小控制在 -1~1之间 房屋的面积对价格的影响 卧室数量对价格的影响 损失函数 def costFunction(X,y,theta): inner np.power(Xtheta-y,2) return np.sum(inner)/(2*len(X)) 梯度下降 def gradientDescent(X,y,theta,alpha,iters…

“第六十四天” 字扩展和位扩展,外部存储器

存储器和CPU的连接; 现在的计算机MAR&#xff0c;MDR通常集成在CPU内部。存储芯片内只需一个普通的寄存器&#xff08;暂存输入&#xff0c;输出数据&#xff09;。 位扩展&#xff0c;字扩展&#xff0c;字位同时扩展&#xff1b; 位扩展&#xff1a; 位扩展的增加的是主存的…

走势分析:鹰言齐发避险需求减弱、金价仍有走低预期和空间

上交易日周二(11月07日)&#xff1a;国际现货黄金/伦敦金触底回升收跌&#xff0c;虽未收至中轨线下方&#xff0c;令后市仍有偏向震荡或再度走强的预期&#xff0c;但主图短期均线死叉信号保持&#xff0c;并对其产生压力&#xff0c;附图指标也维持空头信号发展&#xff0c;也…

深度学习入门-基于Python的理论与实现摘要记录

基本是《深度学习入门-基于Python的理论与实现》的复制粘贴&#xff0c;以作为日后的检索和查询使用 感知机 感知机接收多个输入信号&#xff0c;输出一个信号。 感知机原理 感知机接收多个输入信号&#xff0c;输出一个信号。 图2-1是一个接收两个输入信号的感知机的例子。…

【软考的故事】软考从泄题风波到机考改革,是何原委?

写在前面 有些日子没写文章了&#xff0c;今天咱不谈技术&#xff0c;就聊聊软考机考改革的事情吧&#xff0c;其实事情的起因还得从上半年的考试泄题舞弊案说起&#xff0c;也是我第一次参加软考&#xff0c;因为我是从事web开发的&#xff0c;所以对网络也是半知半解的&…

基于Qt窗口文件新建_编辑_打开_保存_另存_剪切和复制和粘贴项目(文件操作直接套源码)

# .pro文件 QT += widgetsrequires(qtConfig(filedialog))​HEADERS = mainwindow.hSOURCES = main.cpp \ mainwindow.cppRESOURCES = sdi.qrc​# installtarget.path = $$[QT_INSTALL_EXAMPLES]/widgets/mainwindows/sdiINSTALLS += target​…

昇腾CANN 7.0 黑科技:DVPP硬件加速训练数据预处理,友好解决Host CPU预处理瓶颈

在NPU/GPU上进行模型训练计算&#xff0c;为了充分使用计算资源&#xff0c;一般采用批量数据处理方式&#xff0c;因此一般情况下为提升整体吞吐率&#xff0c;batch值会设置的比较大&#xff0c;常见的batch数为256/512&#xff0c;这样一来&#xff0c;对数据预处理处理速度…