RestTemplate 介绍 用于同步客户端HTTP访问的Spring scentral类。它简化了与httpserver的通信,并实施了RESTful原则。它处理HTTP连接,让应用程序代码提供url(带有可能的模板变量)并提取结果。(简化了发起HTTP请求以及处理响应的过程,并且支持REST。)
RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。
静态属性配置超时时间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import lombok.extern.slf4j.Slf4j;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import org.springframework.web.client.RestTemplate;@Slf4j public class RestTemplateUtils { public static final RestTemplate REST_TEMPLATE; static { REST_TEMPLATE = new RestTemplate (); HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory (); clientHttpRequestFactory.setConnectionRequestTimeout(60000 ); clientHttpRequestFactory.setConnectTimeout(60000 ); clientHttpRequestFactory.setReadTimeout(60000 ); REST_TEMPLATE.setRequestFactory(clientHttpRequestFactory); } }
Spring Bean
配置类创建HttpClientConfig
类,设置连接池大小、超时时间、重试机制等。配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 @Configuration public class HttpClientConfig { private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientConfig.class); @Resource private HttpClientProperties p; @Bean public PoolingHttpClientConnectionManager poolingConnectionManager () { SSLContextBuilder builder = new SSLContextBuilder (); try { builder.loadTrustMaterial(null , new TrustStrategy () { public boolean isTrusted (X509Certificate[] arg0, String arg1) { return true ; } }); } catch (NoSuchAlgorithmException | KeyStoreException e) { LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); } SSLConnectionSocketFactory sslsf = null ; try { sslsf = new SSLConnectionSocketFactory (builder.build()); } catch (KeyManagementException | NoSuchAlgorithmException e) { LOGGER.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); } Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder .<ConnectionSocketFactory>create() .register("https" , sslsf) .register("http" , new PlainConnectionSocketFactory ()) .build(); PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager (socketFactoryRegistry); poolingConnectionManager.setMaxTotal(p.getMaxTotalConnections()); poolingConnectionManager.setDefaultMaxPerRoute(p.getDefaultMaxPerRoute()); return poolingConnectionManager; } @Bean public ConnectionKeepAliveStrategy connectionKeepAliveStrategy () { return new ConnectionKeepAliveStrategy () { @Override public long getKeepAliveDuration (HttpResponse response, HttpContext httpContext) { 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 && param.equalsIgnoreCase("timeout" )) { return Long.parseLong(value) * 1000 ; } } return p.getDefaultKeepAliveTimeMillis(); } }; } @Bean public CloseableHttpClient httpClient () { RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(p.getRequestTimeout()) .setConnectTimeout(p.getConnectTimeout()) .setSocketTimeout(p.getSocketTimeout()).build(); return HttpClients.custom() .setDefaultRequestConfig(requestConfig) .setConnectionManager(poolingConnectionManager()) .setKeepAliveStrategy(connectionKeepAliveStrategy()) .setRetryHandler(new DefaultHttpRequestRetryHandler (3 , true )) .build(); } @Bean public Runnable idleConnectionMonitor (final PoolingHttpClientConnectionManager connectionManager) { return new Runnable () { @Override @Scheduled(fixedDelay = 10000) public void run () { try { if (connectionManager != null ) { LOGGER.trace("run IdleConnectionMonitor - Closing expired and idle connections..." ); connectionManager.closeExpiredConnections(); connectionManager.closeIdleConnections(p.getCloseIdleConnectionWaitTimeSecs(), TimeUnit.SECONDS); } else { LOGGER.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised" ); } } catch (Exception e) { LOGGER.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}" , e.getMessage(), e); } } }; } @Bean public TaskScheduler taskScheduler () { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler (); scheduler.setThreadNamePrefix(" poolScheduler" ); scheduler.setPoolSize(50 ); return scheduler; } }
然后再配置RestTemplateConfig类,使用之前配置好的CloseableHttpClient类注入,同时配置一些默认的消息转换器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) public class RestTemplateConfig { @Resource private CloseableHttpClient httpClient; @Bean public RestTemplate restTemplate (MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) { RestTemplate restTemplate = new RestTemplate (clientHttpRequestFactory()); List<HttpMessageConverter<?>> messageConverters = new ArrayList <>(); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter (Charset.forName("utf-8" )); messageConverters.add(stringHttpMessageConverter); messageConverters.add(jackson2HttpMessageConverter); restTemplate.setMessageConverters(messageConverters); return restTemplate; } @Bean public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory () { HttpComponentsClientHttpRequestFactory rf = new HttpComponentsClientHttpRequestFactory (); rf.setHttpClient(httpClient); return rf; } }
附 自定义异常处理器 1 2 3 4 5 6 7 8 9 REST_TEMPLATE.setErrorHandler(new DefaultResponseErrorHandler () { @Override public void handleError (ClientHttpResponse response) throws IOException { if (!HttpStatus.BAD_REQUEST.equals(response.getStatusCode())) { super .handleError(response); } } });
本文地址: https://github.com/maxzhao-it/blog/post/63856b15/