RestTemplate 支持的 HTTP 库
通用接口
- ClientHttpRequestFactory
默认实现
- SimpleClientHttpRequestFactory(什么都不配 自动用这个)
Apache HttpComponents
- HttpComponentsClientHttpRequestFactory (常用)
Netty
- Netty4ClientHttpRequestFactory(已经逐渐被淘汰)
OkHttp
- OkHttp3ClientHttpRequestFactory(主要用于安卓)
连接复用
代码实现
return Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE))//获取KEEP_ALIVE响应头
.stream()//转换成文本
.filter(header -> StringUtils.equalsIgnoreCase(header.getName(),"timeout")&&StringUtils.isNumeric(header.getValue()))//在里面找到timeout这个属性并判断有没有 判断Value是不是个数字
//如果是数字 将文本转换成long类型 如果转换失败 会使用默认值代替(30s) 如果没有取到这个头 也会使用默认值 如果有KEEP_ALIVE头,就使用KEEP_ALIVE头里面设置的timeout 没有的话 这个连接视为永久有效
.findFirst()
.map(header -> NumberUtils.toLong(header.getValue(),DEF))
.orElse(DEF)*1000;
默认实现
- org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy
实例
@SpringBootApplication
@Slf4j
public class CustomerServiceApplication implements ApplicationRunner {
@Autowired
private RestTemplate restTemplate;
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(CustomerServiceApplication.class)
.bannerMode(Banner.Mode.OFF)
.web(WebApplicationType.NONE)
.run(args);
}
@Bean
public HttpComponentsClientHttpRequestFactory requestFactory() {
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);//构造一个连接池的连接管理器 生命周期30s
connectionManager.setMaxTotal(200);//最大保持连接数
connectionManager.setDefaultMaxPerRoute(20);//设置每个路由的最大连接
CloseableHttpClient httpClient = HttpClients.custom()//定制HttpClients
.setConnectionManager(connectionManager) //设置连接管理器
.evictIdleConnections(30, TimeUnit.SECONDS)//空闲连接退出时间
.disableAutomaticRetries()//关闭自动重试 重试:请求处理的时候,系统进行了处理,但是返回响应的时候,没有把响应返回,客户端,会认为该操作没有成功,会再次尝试。这对于打款之类的敏感操作是有问题的
// 有 Keep-Alive 认里面的值,没有的话永久有效
//.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE) 也可以使用官方提供的请求策略
// 换成自定义的
.setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())//设置请求策略
.build();
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);//使用httpClient 构造请求工厂
return requestFactory;
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
// return new RestTemplate();
return builder
.setConnectTimeout(Duration.ofMillis(100))//设置连接超时
.setReadTimeout(Duration.ofMillis(500))//设置读取超时
.requestFactory(this::requestFactory)
.build();
}
@Override
public void run(ApplicationArguments args) throws Exception {
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:8080/coffee/?name={name}")
.build("mocha");
RequestEntity<Void> req = RequestEntity.get(uri)
.accept(MediaType.APPLICATION_XML)
.build();
ResponseEntity<String> resp = restTemplate.exchange(req, String.class);
log.info("Response Status: {}, Response Headers: {}", resp.getStatusCode(), resp.getHeaders().toString());
log.info("Coffee: {}", resp.getBody());
String coffeeUri = "http://localhost:8080/coffee/";
Coffee request = Coffee.builder()
.name("Americano")
.price(Money.of(CurrencyUnit.of("CNY"), 25.00))
.build();
Coffee response = restTemplate.postForObject(coffeeUri, request, Coffee.class);
log.info("New Coffee: {}", response);
ParameterizedTypeReference<List<Coffee>> ptr =
new ParameterizedTypeReference<List<Coffee>>() {};
ResponseEntity<List<Coffee>> list = restTemplate
.exchange(coffeeUri, HttpMethod.GET, null, ptr);
list.getBody().forEach(c -> log.info("Coffee: {}", c));
}
}
结果
分析
定制RestTemplate,实际上就是定制一个HttpComponentsClientHttpRequestFactory和CustomConnectionKeepAliveStrategy,在定制的过程中,disableAutomaticRetries,最好是要加上,下游,同样,做一个请求的need