适配不同场景的RestTemplate

news2025/1/16 18:57:17

一个基本实现

如果项目里可能只是偶尔通过一个url,发起一个http请求,一个基本实现如下:

@Configuration
public class RestTemplateConfiguration {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        // 这个转换器非必须,根据自己的场景添加
        restTemplate.getMessageConverters().set(1,
                new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }
}

进行一下测试:

很好,没有问题。

配置超时

默认实现,比如读取超时或者连接超时是没有限制,我们想自定义,实现如下:

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate(factory);
        // 这个转换器非必须,根据自己的场景添加
        restTemplate.getMessageConverters().set(1,
                new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }

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

我们可以定义一个ClientHttpRequestFactory并配置超时时间来初始化RestTemplate。

RestTemplate默认也是用的ClientHttpRequestFactory的。

支持连接池

默认的ClientHttpRequestFactory使用的是HttpUrlConnection,本身是不支持连接池的,这个时候我们需要启用连接池的实现来提高一个吞吐量或者减少请求响应时间,怎么办。

替换默认的ClientHttpRequestFactory,如下,我们使用支持 Apache HttpComponents HttpClient的实现。

    @Bean(name = "clientHttpRequestFactory")
    public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient client) {

        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new
                HttpComponentsClientHttpRequestFactory(client);
        clientHttpRequestFactory.setConnectTimeout(httpClientProperties.getConnectTimeout());
        clientHttpRequestFactory.setReadTimeout(httpClientProperties.getReadTimeout());
        clientHttpRequestFactory.setConnectionRequestTimeout(httpClientProperties.getAcquireConnectionTimeout());
        return clientHttpRequestFactory;
    }

    @Bean
    public HttpClient httpClient() {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        try {
            // 针对https协议相关配置
            SSLContext sslContext = SSLContext.getInstance("SSL");// 获取一个SSLContext实例
            TrustManager[] trustAllCerts = {new InsecureTrustManager()};
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());// 初始化SSLContext实例

            //设置信任ssl访问
            httpClientBuilder.setSSLContext(sslContext);
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    // 注册http和https请求
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory).build();
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            poolingHttpClientConnectionManager.setMaxTotal(httpClientProperties.getMaxConnection());
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientProperties.getMaxConnectionRoute());
            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientProperties.getRetryTimes(), true));

            //设置默认请求头
            List<Header> headers = getDefaultHeaders();
            httpClientBuilder.setDefaultHeaders(headers);

            httpClientBuilder.evictExpiredConnections();
            httpClientBuilder.evictIdleConnections(httpClientProperties.getIdleTime(), TimeUnit.MINUTES);
            CloseableHttpClient httpClient = httpClientBuilder.build();
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    log.error("close http client error.", e);
                }
            }));
            return httpClient;
        } catch (Exception e) {
            log.error("HttpClient create error.", e);
        }
        return null;
    }

    private List<Header> getDefaultHeaders() {
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("Connection", "Keep-Alive"));
        return headers;
    }

    class InsecureTrustManager implements X509TrustManager {

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}

        /**
         * 返回受信任的X509证书数组
         */
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

    }

 好吧,这里的代码就有点多了,其中使用的HttpClientProperties类主要是其中的一些属性配置,如下:

public class HttpClientProperties {

    private int readTimeout;

    private int connectTimeout;

    private int acquireConnectionTimeout;

    private int maxConnection;

    private int maxConnectionRoute;

    private int retryTimes;

    private int idleTime;
}

这样,再创建RestTemplate的时候,我们可以指定使用支持连接池的ClientHttpRequestFactory,如下:

    @Resource(name = "clientHttpRequestFactory")
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate.getMessageConverters().set(1,
                new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }

支持服务发现

我们的项目里集成了注册中心,需要支持服务发现,负载均衡调用,加个注解即可,如下:

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

注意,这种的就不支持普通的url调用了。

服务发现与普通URL

如果项目里既需要支持服务发现进行调用,又需要调用一些常规的http url的接口,也很简单,定义两个,需要哪个注入哪个:

    @LoadBalanced
    @Bean(name = "loadBalancedRestTemplate")
    public RestTemplate loadBalancedRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }

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

响应状态错误码处理

默认实现,如果是4xx或5xx错误,请求响应的时候会抛出异常:

 在我们的一些场景中,某些接口可能会通过返回不同的状态码来返回不同的错误信息,而不是都返回一个200的状态码,在消息体使用code等字段来表示,如果是4xx或5xx的时候不希望抛异常,而由我们自己获取判断处理,可以如下定义:

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().set(1,
                new StringHttpMessageConverter(Charset.forName("UTF-8")));
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse response) throws IOException {
                return false;
            }

            @Override
            public void handleError(ClientHttpResponse response) throws IOException {

            }
        });
        return restTemplate;
    }

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

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

相关文章

项目常遇到的问题

这里写自定义目录标题1&#xff1a;uniapp生成二维码2&#xff1a;uniapp onShow接收参数3&#xff1a;javascript如何获取对象的key和value4&#xff1a;uni-app&#xff1a;页面直接传递复杂参数5&#xff1a;js对于数组元素相同的分类方法1&#xff1a;uniapp生成二维码 选择…

关联式容器(Associative Container)

1:什么是关联式容器&#xff1f; 关联式容器依照特定的排序准则 自动为元素排序 元素可以是任何类型的value 也可以是 key/value pair key可以是任何类型 映射至一个相关value 而value也可以是任意类型 通常是所有容器默认以<进行比较 也可以通过自己的比较函数 定义出不同的…

Dubbo基础

目录 什么是 RPC 那为什么要有 RPC&#xff0c;HTTP 不好么&#xff1f; RPC 的原理是什么? 如何设计一个 RPC 框架 从底向上的思路 服务消费者 服务提供者 注册中心 监控运维 小结一下 简单实现一个 RPC 框架 Dubbo 简介 Dubbo的历史 Dubbo的功能 为什么要用 …

Java语法之继承

上次给大家分享了Java的封装&#xff0c;今天小编给大家分享面向对象三大特性的第二大特性&#xff0c;也就是继承&#xff0c;fighting~~ 目录 &#x1f384;一.继承的概念 &#x1f384;1.1为什么需要继承 &#x1f384;1.2继承的概念 &#x1f384;1.3继承的语法 &#…

Android App开发中补间动画的讲解以及实现钟摆动画效果实战(附源码 简单易懂 可直接使用)

需要图片集和源码请点赞关注收藏后评论区留言~~~ 一、补间动画的种类 Android提供了补间动画&#xff0c;它允许开发者实现某个视图的动态变换&#xff0c;具体包括四种动画效果&#xff0c;分别是灰度动画&#xff0c;平移动画&#xff0c;缩放动画和旋转动画。因为开发者提供…

缓存穿透、缓存击穿、缓存雪崩区别和解决方案

生命无罪&#xff0c;健康万岁&#xff0c;我是laity。 我曾七次鄙视自己的灵魂&#xff1a; 第一次&#xff0c;当它本可进取时&#xff0c;却故作谦卑&#xff1b; 第二次&#xff0c;当它在空虚时&#xff0c;用爱欲来填充&#xff1b; 第三次&#xff0c;在困难和容易之…

【c++】类和对象

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 3.1类的两种定义方式&#xff1a; 4.类的访问限定符及封装 4.1访问限定符 5.类的作用域 6.类的实例化 7.类对象模型 7.1 如何计算类对象的大小 8.this指针 8.1 this指针的引出 8.2 this指针的特性 9.类的6个默认成员函…

深度学习简介及反向传播

Datawhale开源学习&#xff0c;机器学习课程&#xff0c;项目地址&#xff1a;https://github.com/datawhalechina/leeml-notes 之前学习机器学习的时候&#xff0c;总结了三步&#xff1a; define a set of functiongoodness of functionpick the best function 这三步所做的…

机器学习之决策树【西瓜书】

当一个有经验的老农看一个瓜是不是好瓜时&#xff0c;他可能会先看下瓜的颜色&#xff0c;一看是青绿的&#xff0c;心想有可能是好瓜&#xff1b;接着他又看了下根蒂&#xff0c;发现是蜷缩着的&#xff0c;老农微微点头&#xff0c;寻思着五成以上是好瓜&#xff1b;最后他又…

基于51单片机的客车辆超载报警Proteus仿真

资料编号&#xff1a;111 下面是相关功能视频演示&#xff1a; 111-基于51单片机的客车辆超载报警Proteus仿真&#xff08;源码仿真原理图全套资料&#xff09;功能如下&#xff1a; 利用单片机设计一个超载检测控制电路。 通过 2 组红外对管(类似电路模拟)检测上车人数和下车…

Flink-水位线的设置以及传递

6.2 水位线 6.2.1 概述 分类 有序流 无序流 判断的时间延迟 延迟时间判定 6.2.2 水位线的设置 分析 DataStream下的assignTimstampsAndWatermarks方法&#xff0c;返回SingleOutputStreamOperator本质还是个算子&#xff0c;传入的参数是WatermarkStrategy的生成策略 但…

C51 - 中断系统

Contents1> 定义2> 作用3> 组成3.1> 中断系统结构3.2> 8个中断源3.3> 中断向量3.4> 中断优先级4> 原理5> 应用1> 定义 中断&#xff08;interrupt&#xff09;是指&#xff1a; CPU执行某一程序过程中&#xff0c;由于系统内&#xff0c;或外部某…

【操作文件的系统调用】

目录文件操作系统调用的基本库函数打开文件读取文件写入文件关闭文件应用文件操作代码举例文件操作与进程复制的结合先打开文件再复制进程先进程复制&#xff0c;再进行打开文件缓冲区的知识回顾在上一篇讲述僵尸进程的文章中对文件的系统调用做了一点点的代码讲述&#xff0c;…

day08 微服务保护

1、JMeter压力测试 1.1、安装启动 JMeter 依赖于JDK&#xff0c;所以必须确保当前计算机上已经安装了 JDK&#xff0c;并且配置了环境变量。 Apache Jmeter官网下载&#xff0c;地址&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 解压缩即可使用&#xff0c;目…

【Acwing—单源最短路:建图】

y总说&#xff0c;图论题的难点不在于打板子&#xff0c;而是建图的过程 个人觉得&#xff0c;建图的过程分成以下阶段&#xff1a; 1.确定结点的意义 2.确定边权的意义 结点一般都很显然&#xff0c;但是边权的意义我们一般把它设成对答案&#xff08;或需要维护的东西&am…

C++入门知识(二)

最近太忙了&#xff0c;发论文写开题&#xff0c;有两周时间没有学习C了&#xff0c;因为都是抽时间来学习&#xff0c;所以本篇博客也是零零散散的&#xff0c;接下来尽量抽时间吧 目录 六、引用 6.1 引用概念 6.2 引用特性 6.3 常引用 6.4 使用场景 6.5 传值、传引用…

并发编程(一)可见性

【并发编程三大特性】&#xff1a; 可见性 有序性 原子性&#xff08; 较复杂 &#xff09; 【线程的可见性】&#xff1a; 【一个例子认识线程的可见性】&#xff1a; import Utils.SleepHelper; import java.io.IOException;public class T01_HelloVolatile {private sta…

Go中的泛型和反射以及序列化

嗨喽,小伙伴们,好几没有更新了,最近在搞一些云原生的东西,docker , k8s 搞得我暂时迷失了方向,不过我举得搞IT吗,就是在不断尝试,搞一下当下最新的技术,不然 … GO中的泛型与继承 搞过java的都知道泛型与继承,在go中也开始搞泛型与继承了(在go1.8之后) 先看代码–>> p…

【记录】PyCharm 安装 preprocess 模块(库)|| 在 PyCharm 中安装 preprocess 失败,故而在 终端 安装

preprocess.py 针对的是处理许多 文件类型。它工作的语言包括&#xff1a;C、Python、 perl、tcl、xml、javascript、css、idl、tex、fortran、php、java、shell 脚本&#xff08;bash、csh等&#xff09;和c。预处理可以作为 命令行应用程序和作为python 模块。 目录一、在 Py…

矩阵论复习提纲

矩阵论复习提纲 第一章 矩阵相似变化 1、特征值与特征向量 A ∈ Cnxn 若存在 λ ∈ C 满足 Ax λx 则 λ 为 A 的特征值 可转换为 &#xff08;λI - A&#xff09;x 0 特征多项式 &#xff1a;det(λI - A) 特征矩阵&#xff1a; λI - A 2、相似对角化 1. 判断可对角化…