适配不同场景的RestTemplate
创始人
2024-04-10 11:03:40
0

一个基本实现

如果项目里可能只是偶尔通过一个url,发起一个http请求,一个基本实现如下:

@Configuration
public class RestTemplateConfiguration {@Beanpublic RestTemplate restTemplate() {RestTemplate restTemplate = new RestTemplate();// 这个转换器非必须,根据自己的场景添加restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(Charset.forName("UTF-8")));return restTemplate;}
}

进行一下测试:

很好,没有问题。

配置超时

默认实现,比如读取超时或者连接超时是没有限制,我们想自定义,实现如下:

    @Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate = new RestTemplate(factory);// 这个转换器非必须,根据自己的场景添加restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(Charset.forName("UTF-8")));return restTemplate;}@Beanpublic ClientHttpRequestFactory clientHttpRequestFactory() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setReadTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(3000);return simpleClientHttpRequestFactory;}

我们可以定义一个ClientHttpRequestFactory并配置超时时间来初始化RestTemplate。

RestTemplate默认也是用的ClientHttpRequestFactory的。

支持连接池

默认的ClientHttpRequestFactory使用的是HttpUrlConnection,本身是不支持连接池的,这个时候我们需要启用连接池的实现来提高一个吞吐量或者减少请求响应时间,怎么办。

替换默认的ClientHttpRequestFactory,如下,我们使用支持 Apache HttpComponents HttpClient的实现。

    @Bean(name = "clientHttpRequestFactory")public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient client) {HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = newHttpComponentsClientHttpRequestFactory(client);clientHttpRequestFactory.setConnectTimeout(httpClientProperties.getConnectTimeout());clientHttpRequestFactory.setReadTimeout(httpClientProperties.getReadTimeout());clientHttpRequestFactory.setConnectionRequestTimeout(httpClientProperties.getAcquireConnectionTimeout());return clientHttpRequestFactory;}@Beanpublic HttpClient httpClient() {HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();try {// 针对https协议相关配置SSLContext sslContext = SSLContext.getInstance("SSL");// 获取一个SSLContext实例TrustManager[] trustAllCerts = {new InsecureTrustManager()};sslContext.init(null, trustAllCerts, new java.security.SecureRandom());// 初始化SSLContext实例//设置信任ssl访问httpClientBuilder.setSSLContext(sslContext);HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);Registry socketFactoryRegistry = RegistryBuilder.create()// 注册http和https请求.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslConnectionSocketFactory).build();PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);poolingHttpClientConnectionManager.setMaxTotal(httpClientProperties.getMaxConnection());poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientProperties.getMaxConnectionRoute());httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientProperties.getRetryTimes(), true));//设置默认请求头List
headers = getDefaultHeaders();httpClientBuilder.setDefaultHeaders(headers);httpClientBuilder.evictExpiredConnections();httpClientBuilder.evictIdleConnections(httpClientProperties.getIdleTime(), TimeUnit.MINUTES);CloseableHttpClient httpClient = httpClientBuilder.build();Runtime.getRuntime().addShutdownHook(new Thread(() -> {try {httpClient.close();} catch (IOException e) {log.error("close http client error.", e);}}));return httpClient;} catch (Exception e) {log.error("HttpClient create error.", e);}return null;}private List
getDefaultHeaders() {List
headers = new ArrayList<>();headers.add(new BasicHeader("Connection", "Keep-Alive"));return headers;}class InsecureTrustManager implements X509TrustManager {@Overridepublic void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}/*** 返回受信任的X509证书数组*/@Overridepublic X509Certificate[] getAcceptedIssuers() {return null;}}

 好吧,这里的代码就有点多了,其中使用的HttpClientProperties类主要是其中的一些属性配置,如下:

public class HttpClientProperties {private int readTimeout;private int connectTimeout;private int acquireConnectionTimeout;private int maxConnection;private int maxConnectionRoute;private int retryTimes;private int idleTime;
}

这样,再创建RestTemplate的时候,我们可以指定使用支持连接池的ClientHttpRequestFactory,如下:

    @Resource(name = "clientHttpRequestFactory")@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {RestTemplate restTemplate = new RestTemplate(factory);restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(Charset.forName("UTF-8")));return restTemplate;}

支持服务发现

我们的项目里集成了注册中心,需要支持服务发现,负载均衡调用,加个注解即可,如下:

    @LoadBalanced@Beanpublic RestTemplate restTemplate() {RestTemplate restTemplate = new RestTemplate();return restTemplate;}

注意,这种的就不支持普通的url调用了。

服务发现与普通URL

如果项目里既需要支持服务发现进行调用,又需要调用一些常规的http url的接口,也很简单,定义两个,需要哪个注入哪个:

    @LoadBalanced@Bean(name = "loadBalancedRestTemplate")public RestTemplate loadBalancedRestTemplate() {RestTemplate restTemplate = new RestTemplate();return restTemplate;}@Bean(name = "restTemplate")public RestTemplate restTemplate() {RestTemplate restTemplate = new RestTemplate();return restTemplate;}

响应状态错误码处理

默认实现,如果是4xx或5xx错误,请求响应的时候会抛出异常:

 在我们的一些场景中,某些接口可能会通过返回不同的状态码来返回不同的错误信息,而不是都返回一个200的状态码,在消息体使用code等字段来表示,如果是4xx或5xx的时候不希望抛异常,而由我们自己获取判断处理,可以如下定义:

    @Beanpublic RestTemplate restTemplate() {RestTemplate restTemplate = new RestTemplate();restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(Charset.forName("UTF-8")));restTemplate.setErrorHandler(new ResponseErrorHandler() {@Overridepublic boolean hasError(ClientHttpResponse response) throws IOException {return false;}@Overridepublic void handleError(ClientHttpResponse response) throws IOException {}});return restTemplate;}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...