实战代码(十):Springboot RestTemplate连接池
一、理论基础
RestTemplate是Springboot中内置的Http请求工具,可以直接注入使用。
两个常用的构造方法如下图 (点击进入文档地址)

从上面可以看出,最简单的方式就是使用默认配置,不需要额外的配置,便可以直接使用该工具。对于请求频次比较低的情况下,默认配置完全够用。
如果需要大量的请求,可以自定义配置,使用HttpClient的连接池。
二、实战代码
2.1 依赖引入
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-undertow org.springframework.boot spring-boot-configuration-processor true org.apache.httpcomponents httpclient 4.5.12 com.alibaba fastjson 1.2.62 org.projectlombok lombok true 2.2 配置项
2.2.1 配置
http: pool: # 连接超时 connectTimeout: 5000 connectionRequestTimeout: 5000 defaultMaxPerRoute: 20 # 最大连接数 maxTotal: 100 # 服务器返回数据(response)的时间 socketTimeout: 5000 validateAfterInactivity: 30000 2.2.2 读取配置文件
@Component @ConfigurationProperties(prefix = "http.pool") @Data public class HttpClientProperties { /** * 最大连接数 */ private Integer maxTotal; /** * 路由是对最大连接数的细分 * 每个路由基础的连接数 */ private Integer defaultMaxPerRoute; /** * 连接超时时间 */ private Integer connectTimeout; /** * 从连接池中获取连接的超时时间 */ private Integer connectionRequestTimeout; /** * 服务器返回数据(response)的时间 */ private Integer socketTimeout; /** * 可用空闲连接过期时间 * 重用空闲连接时会先检查是否空闲时间超过这个时间,如果超过,释放socket重新建立 */ private Integer validateAfterInactivity; } 2.3 配置文件
@Configuration public class RestTemplateConfig { private final HttpClientProperties httpClientProperties; public RestTemplateConfig(HttpClientProperties httpClientProperties) { this.httpClientProperties = httpClientProperties; } @Bean public RestTemplate restTemplate(ClientHttpRequestFactory factory){ return new RestTemplate(factory); } @Bean public ClientHttpRequestFactory clientHttpRequestFactory(){ return new HttpComponentsClientHttpRequestFactory(httpClient()); } @Bean public HttpClient httpClient() { Registry registry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); connectionManager.setMaxTotal(httpClientProperties.getMaxTotal()); connectionManager.setDefaultMaxPerRoute(httpClientProperties.getDefaultMaxPerRoute()); connectionManager.setValidateAfterInactivity(httpClientProperties.getValidateAfterInactivity()); RequestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(httpClientProperties.getSocketTimeout()) .setConnectTimeout(httpClientProperties.getConnectTimeout()) .setConnectionRequestTimeout(httpClientProperties.getConnectionRequestTimeout()) .build(); return HttpClientBuilder.create() .setDefaultRequestConfig(requestConfig) .setConnectionManager(connectionManager) .build(); } } 2.4 简单的工具类
@Component @Slf4j public class HttpClientUtils { private final RestTemplate restTemplate; public HttpClientUtils(RestTemplate restTemplate) { this.restTemplate = restTemplate; } /** * Get */ public String get(String uri, Map param, String token) { HttpHeaders headers = new HttpHeaders(); headers.set("token", token); HttpEntity requestEntity = new HttpEntity<>(null, headers); StringBuilder url = new StringBuilder(); url.append(uri).append("?"); param.forEach((k, v) -> url.append(k).append("=").append(v).append("&")); String getUrl = url.substring(0, url.length() - 1); ResponseEntity response = restTemplate.exchange(getUrl, HttpMethod.GET, requestEntity, CodeResult.class); return parseCodeResult(response); } /** * post方式请求接口 * - 参数形式:form-data */ public String postFormData(String url, MultiValueMap paramMap, String token) { HttpHeaders headers = new HttpHeaders(); headers.set("token", token); headers.setContentType(MediaType.MULTIPART_FORM_DATA); //用HttpEntity封装整个请求报文 HttpEntity> files = new HttpEntity<>(paramMap, headers); ResponseEntity response = restTemplate.postForEntity(url, files, CodeResult.class); return parseCodeResult(response); } /** * post方式请求接口 * - 参数形式:json */ public String postJson(String url, String param, String token) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("token", token); HttpEntity entity = new HttpEntity<>(param, headers); ResponseEntity response = restTemplate.postForEntity(url, entity, CodeResult.class); return parseCodeResult(response); } /** * 解析云端服务接口返回值 */ public String parseCodeResult(ResponseEntity response) { if (response.getStatusCodeValue() != HttpStatus.OK.value()) { throw new RuntimeException("网络请求失败,状态码:" + response.getStatusCodeValue()); } CodeResult codeResult = response.getBody(); assert codeResult != null; if (!codeResult.getSuccess()) { log.error("调用后台服务接口错误,返回值:{}", JSON.toJSON(codeResult)); throw new RuntimeException("调用后台服务接口错误, 错误信息:" + codeResult.getMsg()); } return JSON.toJSONString(codeResult.getData()); } } 三、源码地址
https://github.com/lysmile/spring-boot-demo/tree/master/spring-boot-resttemplate-demo
下一个:面试官:请用SQL模拟一个死锁