发布于2021-04-02 06:36 阅读(3987) 评论(0) 点赞(11) 收藏(5)
一,建立配置属性文件
- spring:
- http-client:
- pool:
- #连接池的最大连接数,0代表不限;如果取0,需要考虑连接泄露导致系统崩溃的后果
- maxTotalConnect: 1000
- #每个路由的最大连接数,如果只调用一个地址,可以将其设置为最大连接数
- maxConnectPerRoute: 200
- # 指客户端和服务器建立连接的超时时间,ms , 最大约21秒,因为内部tcp在进行三次握手建立连接时,默认tcp超时时间是20秒
- connectTimeout: 3000
- # 指客户端从服务器读取数据包的间隔超时时间,不是总读取时间,也就是socket timeout,ms
- readTimeout: 5000
- # 从连接池获取连接的timeout,不宜过大,ms
- connectionRequestTimout: 200
- # 重试次数
- retryTimes: 3
- charset: UTF-8
- # 长连接保持时间 单位s,不宜过长
- keepAliveTime: 10
- keepAliveTargetHost:
- www.baidu.com: 5
二,创建配置属性类
- package com.aishua.zdjfzxq.config;
-
- import org.springframework.boot.context.properties.ConfigurationProperties;
- import org.springframework.stereotype.Component;
-
- import java.util.Map;
-
- /**
- * @Author: zh
- * @Date:
- * @Description:
- */
- @Component
- @ConfigurationProperties(prefix = "spring.http-client.pool")
- public class HttpClientPoolConfig {
-
- /**
- * java配置的优先级低于yml配置;如果yml配置不存在,会采用java配置
- */
-
- /**
- * 连接池的最大连接数
- */
- private int maxTotalConnect ;
- /**
- * 同路由的并发数
- */
- private int maxConnectPerRoute ;
- /**
- * 客户端和服务器建立连接超时,默认2s
- */
- private int connectTimeout = 2 * 1000;
- /**
- * 指客户端从服务器读取数据包的间隔超时时间,不是总读取时间,默认30s
- */
- private int readTimeout = 30 * 1000;
-
- private String charset = "UTF-8";
- /**
- * 重试次数,默认2次
- */
- private int retryTimes = 2;
- /**
- * 从连接池获取连接的超时时间,不宜过长,单位ms
- */
- private int connectionRequestTimout = 200;
- /**
- * 针对不同的地址,特别设置不同的长连接保持时间
- */
- private Map<String,Integer> keepAliveTargetHost;
- /**
- * 针对不同的地址,特别设置不同的长连接保持时间,单位 s
- */
- private int keepAliveTime = 60;
-
- public int getMaxTotalConnect() {
- return maxTotalConnect;
- }
-
- public void setMaxTotalConnect(int maxTotalConnect) {
- this.maxTotalConnect = maxTotalConnect;
- }
-
- public int getMaxConnectPerRoute() {
- return maxConnectPerRoute;
- }
-
- public void setMaxConnectPerRoute(int maxConnectPerRoute) {
- this.maxConnectPerRoute = maxConnectPerRoute;
- }
-
- public int getConnectTimeout() {
- return connectTimeout;
- }
-
- public void setConnectTimeout(int connectTimeout) {
- this.connectTimeout = connectTimeout;
- }
-
- public int getReadTimeout() {
- return readTimeout;
- }
-
- public void setReadTimeout(int readTimeout) {
- this.readTimeout = readTimeout;
- }
-
- public String getCharset() {
- return charset;
- }
-
- public void setCharset(String charset) {
- this.charset = charset;
- }
-
- public int getRetryTimes() {
- return retryTimes;
- }
-
- public void setRetryTimes(int retryTimes) {
- this.retryTimes = retryTimes;
- }
-
- public int getConnectionRequestTimout() {
- return connectionRequestTimout;
- }
-
- public void setConnectionRequestTimout(int connectionRequestTimout) {
- this.connectionRequestTimout = connectionRequestTimout;
- }
-
- public Map<String, Integer> getKeepAliveTargetHost() {
- return keepAliveTargetHost;
- }
-
- public void setKeepAliveTargetHost(Map<String, Integer> keepAliveTargetHost) {
- this.keepAliveTargetHost = keepAliveTargetHost;
- }
-
- public int getKeepAliveTime() {
- return keepAliveTime;
- }
-
- public void setKeepAliveTime(int keepAliveTime) {
- this.keepAliveTime = keepAliveTime;
- }
-
-
- }
三,创建 连接池
- package com.aishua.zdjfzxq.config;
- import com.alibaba.fastjson.JSON;
- import org.apache.http.Header;
- import org.apache.http.HeaderElement;
- import org.apache.http.HeaderElementIterator;
- import org.apache.http.HttpHost;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.protocol.HttpClientContext;
- import org.apache.http.config.Registry;
- import org.apache.http.config.RegistryBuilder;
- import org.apache.http.conn.ConnectionKeepAliveStrategy;
- 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.client.CloseableHttpClient;
- import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
- import org.apache.http.impl.client.HttpClientBuilder;
- import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
- import org.apache.http.message.BasicHeader;
- import org.apache.http.message.BasicHeaderElementIterator;
- import org.apache.http.protocol.HTTP;
- import org.apache.http.ssl.SSLContextBuilder;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
- 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.http.converter.HttpMessageConverter;
- import org.springframework.http.converter.StringHttpMessageConverter;
- import org.springframework.stereotype.Component;
- import org.springframework.web.client.DefaultResponseErrorHandler;
- import org.springframework.web.client.RestTemplate;
-
- import javax.net.ssl.HostnameVerifier;
- import javax.net.ssl.SSLContext;
- import java.nio.charset.Charset;
- import java.security.KeyManagementException;
- import java.security.KeyStoreException;
- import java.security.NoSuchAlgorithmException;
- import java.util.*;
-
- /**
- * @Author: zh
- * @Date:
- * @Description:
- */
- @Configuration
- @Component
- @ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class})
- public class HttpClientConfig {
- private final Logger log = LoggerFactory.getLogger(this.getClass());
-
- @Autowired
- private HttpClientPoolConfig httpClientPoolConfig;
-
- @Bean
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
-
-
- /**
- * 创建HTTP客户端工厂
- */
- @Bean(name = "clientHttpRequestFactory")
- public ClientHttpRequestFactory clientHttpRequestFactory() {
- /**
- * maxTotalConnection 和 maxConnectionPerRoute 必须要配
- */
- if (httpClientPoolConfig.getMaxTotalConnect() <= 0) {
- throw new IllegalArgumentException("invalid maxTotalConnection: " + httpClientPoolConfig.getMaxTotalConnect());
- }
- if (httpClientPoolConfig.getMaxConnectPerRoute() <= 0) {
- throw new IllegalArgumentException("invalid maxConnectionPerRoute: " + httpClientPoolConfig.getMaxConnectPerRoute());
- }
- HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
- // 连接超时
- clientHttpRequestFactory.setConnectTimeout(httpClientPoolConfig.getConnectTimeout());
- // 数据读取超时时间,即SocketTimeout
- clientHttpRequestFactory.setReadTimeout(httpClientPoolConfig.getReadTimeout());
- // 从连接池获取请求连接的超时时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的
- clientHttpRequestFactory.setConnectionRequestTimeout(httpClientPoolConfig.getConnectionRequestTimout());
- return clientHttpRequestFactory;
- }
-
- /**
- * 初始化RestTemplate,并加入spring的Bean工厂,由spring统一管理
- */
- @Bean(name = "httpClientTemplate")
- public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
- return createRestTemplate(factory);
- }
- /**
- * 配置httpClient
- *
- * @return
- */
- @Bean
- public HttpClient httpClient() {
- HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
- try {
- //设置信任ssl访问
- SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
-
- 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();
-
- //使用Httpclient连接池的方式配置(推荐),同时支持netty,okHttp以及其他http框架
- PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
- // 最大连接数
- poolingHttpClientConnectionManager.setMaxTotal(httpClientPoolConfig.getMaxTotalConnect());
- // 同路由并发数
- poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientPoolConfig.getMaxConnectPerRoute());
- //配置连接池
- httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
- // 重试次数
- httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientPoolConfig.getRetryTimes(), true));
-
- //设置默认请求头
- List<Header> headers = getDefaultHeaders();
- httpClientBuilder.setDefaultHeaders(headers);
- //设置长连接保持策略
- httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy());
- return httpClientBuilder.build();
- } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
- log.error("初始化HTTP连接池出错", e);
- }
- return null;
- }
-
-
- /**
- * 配置长连接保持策略
- * @return
- */
- public ConnectionKeepAliveStrategy connectionKeepAliveStrategy(){
- return (response, context) -> {
- // Honor 'keep-alive' header
- HeaderElementIterator it = new BasicHeaderElementIterator(
- response.headerIterator(HTTP.CONN_KEEP_ALIVE));
- while (it.hasNext()) {
- HeaderElement he = it.nextElement();
- String param = he.getName();
- String value = he.getValue();
- if (value != null && "timeout".equalsIgnoreCase(param)) {
- try {
- return Long.parseLong(value) * 1000;
- } catch(NumberFormatException ignore) {
- log.error("解析长连接过期时间异常",ignore);
- }
- }
- }
- HttpHost target = (HttpHost) context.getAttribute(
- HttpClientContext.HTTP_TARGET_HOST);
- //如果请求目标地址,单独配置了长连接保持时间,使用该配置
- Optional<Map.Entry<String, Integer>> any = Optional.ofNullable(httpClientPoolConfig.getKeepAliveTargetHost()).orElseGet(HashMap::new)
- .entrySet().stream().filter(
- e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny();
- //否则使用默认长连接保持时间
- return any.map(en -> en.getValue() * 1000L).orElse(httpClientPoolConfig.getKeepAliveTime() * 1000L);
- };
- }
-
-
-
-
- /**
- * 设置请求头
- *
- * @return
- */
- private List<Header> getDefaultHeaders() {
- List<Header> headers = new ArrayList<>();
- headers.add(new BasicHeader("User-Agent",
- "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
- headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
- headers.add(new BasicHeader("Accept-Language", "zh-CN"));
- headers.add(new BasicHeader("Connection", "Keep-Alive"));
- return headers;
- }
-
-
- private RestTemplate createRestTemplate(ClientHttpRequestFactory factory) {
- RestTemplate restTemplate = new RestTemplate(factory);
-
- //我们采用RestTemplate内部的MessageConverter
- //重新设置StringHttpMessageConverter字符集,解决中文乱码问题
- modifyDefaultCharset(restTemplate);
-
- //设置错误处理器
- restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
-
- return restTemplate;
- }
-
- /**
- * 修改默认的字符集类型为utf-8
- *
- * @param restTemplate
- */
- private void modifyDefaultCharset(RestTemplate restTemplate) {
- List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
- HttpMessageConverter<?> converterTarget = null;
- for (HttpMessageConverter<?> item : converterList) {
- if (StringHttpMessageConverter.class == item.getClass()) {
- converterTarget = item;
- break;
- }
- }
- if (null != converterTarget) {
- converterList.remove(converterTarget);
- }
- Charset defaultCharset = Charset.forName(httpClientPoolConfig.getCharset());
- converterList.add(1, new StringHttpMessageConverter(defaultCharset));
- }
- }
四、使用案例
- package com.aishua.zdjfzxq.service.impl;
-
- import com.aishua.zdjfzxq.entity.ZdjfBatchPlan;
- import com.aishua.zdjfzxq.framework.SingleThreadPullService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.web.client.RestClientException;
- import org.springframework.web.client.RestTemplate;
-
- import javax.annotation.Resource;
- import java.util.Arrays;
- import java.util.List;
- @Service
- public class ZxqPullService implements SingleThreadPullService {
- @Resource
- RestTemplate restTemplate;
- @Resource
- private RestTemplate httpClientTemplate;
- @Override
- public List pullList(int size) {
- String host = "localhost";
- String port = "8080";
- String url = "http://" + host + ":" + port + "/FfqWorkController?name={1}";
- ZdjfBatchPlan[] list= new ZdjfBatchPlan[0];
- try {
- list = httpClientTemplate.getForObject("http://localhost:8080/FfqWorkController/obtain?num={1}",ZdjfBatchPlan[].class,size);
- } catch (RestClientException e) {
- e.printStackTrace();
- }
- return Arrays.asList(list);
- }
- }
作者:忽明忽灭
链接:http://www.javaheidong.com/blog/article/137151/581364ae5b7d556e707e/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!