从Apache HttpClient类库,说一说springboot应用程序中的AutoConfiguration的封装

news2024/11/28 22:50:03

一、背景

在使用httpclient框架请求http接口的时候,我们往往会需要自定义配置httpclient,而非直接使用。

		<dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

在这里插入图片描述

本文仅以自定义httpclient为例,目的是看在springboot应用程序中,如何写一个AutoConfiguration配置类。

涉及到的类有以下六个:

  • HttpClientAutoConfiguration
  • HttpClientProperties
  • ApacheHttpClientConnectionManagerFactory
  • ApacheHttpClientFactory
  • DefaultApacheHttpClientConnectionManagerFactory
  • DefaultApacheHttpClientFactory

在这里插入图片描述
在这里插入图片描述

二、写一个AutoConfiguration

1、HttpClientAutoConfiguration

HttpClientAutoConfiguration类提供了一个自动化配置HTTP客户端的解决方案,使得开发者可以方便地在Spring Boot应用中使用Apache HttpClient库。通过配置文件和自动配置,它创建了HTTP连接管理器和HTTP客户端,并且安排了定时任务来维护这些连接。


import com.google.common.util.concurrent.ThreadFactoryBuilder;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PreDestroy;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


@Configuration
// 使用配置类HttpClientProperties
@EnableConfigurationProperties(value = {HttpClientProperties.class})
public class HttpClientAutoConfiguration {
    private final ScheduledExecutorService scheduledService;
    private CloseableHttpClient httpClient;

    @Autowired
    public HttpClientAutoConfiguration() {
        // 定义一个单线程池
        this.scheduledService = new ScheduledThreadPoolExecutor(
                1,
                new ThreadFactoryBuilder().setNameFormat("http-client-manager").build(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

    @Bean
    @ConditionalOnMissingBean
    public ApacheHttpClientConnectionManagerFactory connManFactory() {
        return new DefaultApacheHttpClientConnectionManagerFactory();
    }

    @Bean
    @ConditionalOnMissingBean
    public HttpClientBuilder apacheHttpClientBuilder() {
        return HttpClientBuilder.create();
    }

    @Bean
    @ConditionalOnMissingBean
    public ApacheHttpClientFactory apacheHttpClientFactory(
            HttpClientBuilder builder) {
        return new DefaultApacheHttpClientFactory(builder);
    }

    /**
     * Connection manager
     */
    @Bean
    @ConditionalOnMissingBean
    public HttpClientConnectionManager connectionManager(
            ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
            HttpClientProperties httpClientProperties) {
        final HttpClientConnectionManager connectionManager = connectionManagerFactory
                .newConnectionManager(httpClientProperties.getDisableSslValidation(),
                        httpClientProperties.getMaxConnections(),
                        httpClientProperties.getMaxConnectionsPerRoute(),
                        httpClientProperties.getTimeToLive(),
                        httpClientProperties.getTimeToLiveUnit());


        // 定时关闭过期的HTTP连接
        this.scheduledService.scheduleWithFixedDelay(connectionManager::closeExpiredConnections, 1000,
                httpClientProperties.getConnectionTimerRepeat(), TimeUnit.MILLISECONDS);

        return connectionManager;
    }

    /**
     * Http client
     */
    @Bean
    @ConditionalOnMissingBean
    public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
                                          HttpClientConnectionManager httpClientConnectionManager,
                                          HttpClientProperties httpClientProperties) {
        RequestConfig defaultRequestConfig = RequestConfig.custom()
                .setConnectTimeout(httpClientProperties.getConnectionTimeout())
                .setRedirectsEnabled(httpClientProperties.getFollowRedirects())
                .build();

        this.httpClient = httpClientFactory
                .createBuilder()
                .setDefaultRequestConfig(defaultRequestConfig)
                .setConnectionManager(httpClientConnectionManager)
                .build();
        return this.httpClient;
    }

    /**
     * Destroy
     */
    @PreDestroy
    // @PreDestroy注解的destroy()方法,用于在应用关闭时执行清理工作,关闭线程池scheduledService和httpClient
    public void destroy() throws Exception {
        this.scheduledService.shutdown();
        if (this.httpClient != null) {
            this.httpClient.close();
        }
    }
}

2、HttpClientProperties配置文件

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.concurrent.TimeUnit;

@Data
@ConfigurationProperties(prefix = "httpclient")
public class HttpClientProperties {

    /**
     * Value for disabling SSL validation.
     */
    private Boolean disableSslValidation = false;

    /**
     * Value for max number od connections.
     */
    private Integer maxConnections = 200;

    /**
     * Value for max number od connections per route.
     */
    private Integer maxConnectionsPerRoute = 50;

    /**
     * Value for time to live.
     */
    private Long timeToLive = 900L;

    /**
     * Time to live unit.
     */
    private TimeUnit timeToLiveUnit = TimeUnit.SECONDS;

    /**
     * Value for following redirects.
     */
    private Boolean followRedirects = true;

    /**
     * Value for connection timeout.
     */
    private Integer connectionTimeout = 2000;

    /**
     * Value for connection timer repeat.
     */
    private Integer connectionTimerRepeat = 3000;
}

3、定义两个工厂接口

  • ApacheHttpClientConnectionManagerFactory
import org.apache.http.conn.HttpClientConnectionManager;

import java.util.concurrent.TimeUnit;

public interface ApacheHttpClientConnectionManagerFactory {
    String HTTP_SCHEME = "http";

    /**
     * Scheme for HTTPS based communication.
     */
    String HTTPS_SCHEME = "https";

    /**
     * Creates a new {@link HttpClientConnectionManager}.
     *
     * @param disableSslValidation   If true, SSL validation will be disabled.
     * @param maxTotalConnections    The total number of connections.
     * @param maxConnectionsPerRoute The total number of connections per route.
     * @param timeToLive             The time a connection is allowed to exist.
     * @param timeUnit               The time unit for the time-to-live value.
     *                               manager.
     * @return A new {@link HttpClientConnectionManager}.
     */
    HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
                                                     int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
                                                     TimeUnit timeUnit);
}

  • ApacheHttpClientFactory
import org.apache.http.impl.client.HttpClientBuilder;

public interface ApacheHttpClientFactory {
    /**
     * Create builder
     *
     * @return HttpClientBuilder
     */
    HttpClientBuilder createBuilder();

4、工厂接口的实现

  • DefaultApacheHttpClientConnectionManagerFactory
import lombok.extern.slf4j.Slf4j;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DefaultApacheHttpClientConnectionManagerFactory implements ApacheHttpClientConnectionManagerFactory {

    @Override
    public HttpClientConnectionManager newConnectionManager(boolean disableSslValidation,
                                                            int maxTotalConnections, int maxConnectionsPerRoute, long timeToLive,
                                                            TimeUnit timeUnit) {
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>create()
                .register(HTTP_SCHEME, PlainConnectionSocketFactory.INSTANCE);

        if (disableSslValidation) {
            try {
                final SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null,
                        new TrustManager[]{new DisabledValidationTrustManager()},
                        new SecureRandom());
                registryBuilder.register(HTTPS_SCHEME, new SSLConnectionSocketFactory(
                        sslContext, NoopHostnameVerifier.INSTANCE));
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                log.warn("Error creating SSLContext", e);
            }
        } else {
            registryBuilder.register("https", SSLConnectionSocketFactory.getSocketFactory());
        }

        final Registry<ConnectionSocketFactory> registry = registryBuilder.build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
                registry, null, null, null, timeToLive, timeUnit);
        connectionManager.setMaxTotal(maxTotalConnections);
        connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);

        return connectionManager;
    }

    static class DisabledValidationTrustManager implements X509TrustManager {

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

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    }
}

  • DefaultApacheHttpClientFactory
import org.apache.http.impl.client.HttpClientBuilder;

public class DefaultApacheHttpClientFactory implements ApacheHttpClientFactory {

    private final HttpClientBuilder builder;

    public DefaultApacheHttpClientFactory(HttpClientBuilder builder) {
        this.builder = builder;
    }

    @Override
    public HttpClientBuilder createBuilder() {
        return this.builder.disableContentCompression().disableCookieManagement()
                .useSystemProperties();
    }
}

三、使用自定义httpclient对象

protected final CloseableHttpClient httpClient;


protected AbstractChannel(CloseableHttpClient httpClient) {
        this.httpClient = httpClient;
    }


protected String postJson(String url, String body) throws IOException {
        RequestConfig requestConfig = RequestConfig.custom()
                // 200 ms
                .setConnectionRequestTimeout(1000)
                // 1000ms
                .setSocketTimeout(1000)
                .build();

        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(requestConfig);
        httpPost.setHeader("Accept", "application/json");
        httpPost.setHeader("Content-Type", "application/json");

        // Execute
        StringEntity entity = new StringEntity(body, StandardCharsets.UTF_8);
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        CloseableHttpResponse response = this.httpClient.execute(httpPost);

        // Response data.
        String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
        int statusCode = response.getStatusLine().getStatusCode();
        response.close();

        // Http code
        if (statusCode != 200) {
            throw new RuntimeException(String.format("http post failed! status=%d %s", statusCode, responseBody));
        }

        return responseBody;
    }

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

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

相关文章

Language2Pose: Natural Language Grounded Pose Forecasting # 论文阅读

URL https://arxiv.org/pdf/1907.01108 TD;DR 19 年 7 月 cmu 的文章&#xff0c;提出一种基于 natural language 生成 3D 动作序列的方法。通过一个简单的 CNN 模型应该就可以实现 Model & Method 首先定义一下任务&#xff1a; 输入&#xff1a;用户的自然语言&…

链表第4/9题--翻转链表--双指针法

LeetCode206&#xff1a;给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例…

科沃斯梦碎“扫地茅”,钱东奇跌落“风口”

昔日“扫地茅“不香了&#xff0c;科沃斯跌落神坛。 4月27日&#xff0c;科沃斯发布2023年报显示&#xff1a;2023年&#xff0c;科沃斯的营收为155.02亿元&#xff0c;同比增加1.16%&#xff1b;同期&#xff0c;净利为6.10亿元&#xff0c;同比减少63.96%。科沃斯的经营业绩…

HR招聘面试测评,如何判断候选人的创新能力?

创新能力代表着一个人的未来发展潜力&#xff0c;创新能力突出的人&#xff0c;未来的上限就可能更高。而对于一个公司而言&#xff0c;一个具有创新能力的员工&#xff0c;会给公司带来新方案&#xff0c;新思路&#xff0c;对公司的长远发展拥有着十分积极的作用。 而在挑选…

【荣耀笔试题汇总】2024-05-09-荣耀春招笔试题-三语言题解(CPP/Python/Java)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新荣耀近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f49…

解析Spring中的循环依赖问题:初探三级缓存

什么是循环依赖&#xff1f; 这个情况很简单&#xff0c;即A对象依赖B对象&#xff0c;同时B对象也依赖A对象&#xff0c;让我们来简单看一下。 // A依赖了B class A{public B b; }// B依赖了A class B{public A a; }这种循环依赖可能会引发问题吗&#xff1f; 在没有考虑Sp…

信息系统项目管理师0097:价值交付系统(6项目管理概论—6.4价值驱动的项目管理知识体系—6.4.6价值交付系统)

点击查看专栏目录 文章目录 6.4.6价值交付系统1.创造价值2.价值交付组件3.信息流6.4.6价值交付系统 价值交付系统描述了项目如何在系统内运作,为组织及其干系人创造价值。价值交付系统包括项目如何创造价值、价值交付组件和信息流。 1.创造价值 项目存在于组织中,包括政府机构…

kkkkkkkkkkkk564

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 人工智能与机器学习 &#x1f4dd;人工智能相关概念☞什么是人工智能、机器学习、深度学习☞人工智能发…

【LeetCode:LCR 077. 排序链表 + 链表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

发表博客之:gemm/threadblock/threadblock_swizzle.h 文件夹讲解,cutlass深入讲解

文章目录 [发表博客之&#xff1a;gemm/threadblock/threadblock_swizzle.h 文件夹讲解&#xff0c;cutlass深入讲解](https://cyj666.blog.csdn.net/article/details/138514145)先来看一下最简单的struct GemmIdentityThreadblockSwizzle结构体 发表博客之&#xff1a;gemm/th…

STM32G030C8T6:EEPROM读写实验(I2C通信)

本专栏记录STM32开发各个功能的详细过程&#xff0c;方便自己后续查看&#xff0c;当然也供正在入门STM32单片机的兄弟们参考&#xff1b; 本小节的目标是&#xff0c;系统主频64 MHZ,采用高速外部晶振&#xff0c;实现PB11,PB10 引脚模拟I2C 时序&#xff0c;对M24C08 的EEPRO…

就业班 第三阶段(zabbix) 2401--5.9 day1 普通集zabbix 5.0部署 nginx部署+agent部署

文章目录 环境一、zabbix 5.0 部署1、安装yum源2、安装相关软件3、数据库安装和配置mariaDB数据库mysql57数据库 安装mysql万能卸载mysql代码&#xff1a;启动mysql并初始化4、数据表导入5、修改配置&#xff0c;启动服务6、配置 web GUI7、浏览器访问注意数据加密的选项不要勾…

基于Springboot的滴答拍摄影

基于SpringbootVue的滴答拍摄影设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 摄影作品 摄影服务 摄影论坛 后台登录 后台首页 用户管理 摄影师管理 摄影作…

谷歌继续将生成式人工智能融入网络安全

谷歌正在将多个威胁情报流与 Gemini 生成人工智能模型相结合&#xff0c;以创建新的云服务。 Google 威胁情报服务旨在帮助安全团队快速准确地整理大量数据&#xff0c;以便更好地保护组织免受网络攻击。 本周在旧金山举行的 RSA 会议上推出的 Google 威胁情报服务吸收了 Mand…

旅游组团奖励标准,申报条件!利川市旅游组团奖励办法

利川市旅游组团奖励有哪些&#xff1f;关于利川市旅游组团奖励标准&#xff0c;申报条件整理如下&#xff1a; 第一条根据《湖北省人民政府办公厅印发关于更好服务市场主体推动经济稳健发展若干政策措施的通知》&#xff08;鄂政办发〔2022〕54号&#xff09;、《恩施州人民政府…

力扣2105---给植物浇水II(Java、模拟、双指针)

题目描述&#xff1a; Alice 和 Bob 打算给花园里的 n 株植物浇水。植物排成一行&#xff0c;从左到右进行标记&#xff0c;编号从 0 到 n - 1 。其中&#xff0c;第 i 株植物的位置是 x i 。 每一株植物都需要浇特定量的水。Alice 和 Bob 每人有一个水罐&#xff0c;最初是…

Centos固定静态ip地址

这里我用的是Vmware虚拟机搭建的三台机器 进入 cd /etc/sysconfig/network-scripts然后使用 ip addr命令&#xff0c;查看自己虚拟机的以太网地址。 我这里是ens33 上面的第一个选项是本地环回地址&#xff0c;不用管它 然后查看刚刚进入的network-scripts目录下的文件 找到…

【机器学习】AI时代的核心驱动力

机器学习&#xff1a;AI时代的核心驱动力 一、引言二、机器学习的基本原理与应用三、机器学习算法概览四、代码实例&#xff1a;线性回归的Python实现 一、引言 在数字化浪潮席卷全球的今天&#xff0c;人工智能&#xff08;AI&#xff09;已经不再是科幻小说中的遥远概念&…

106短信平台疑难解答:为何手机正常却收不到短信?

当您使用群发短信平台发送消息时&#xff0c;有时尽管系统提示发送成功&#xff0c;但手机却未能收到短信。这背后可能隐藏着一些不为人知的原因。 首先&#xff0c;我们要明确&#xff0c;在正常情况下&#xff0c;只要手机状态正常&#xff0c;都应该能够接收到短信。然而&am…

图表控件LightningChart .NET中文教程 - 创建3D网格模型实时着色应用

LightningChart.NET完全由GPU加速&#xff0c;并且性能经过优化&#xff0c;可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D&#xff0c;高级3D&#xff0c;Polar&#xff0c;Smith&#xff0c;3D饼/甜甜圈&#xff0c;地理地图和GIS图表以及适用于科学…