自從RESTFul API興起後,Spring就給開發者提供了一個訪問Rest的客服端,RestTemplate不只能夠很方便的調用http接口,還能夠調用同一註冊中心下的微服務,同時還有負載均衡和熔斷機制。固然我也據說OKhttp,HTTPClient之類的網絡框架,可是咱們這裏重點講的是RestTemplate(其中一種實現就是基於HTTPClient實現的),由於這是SpringBoot自帶,並且基本使用場景都覆蓋了。
RestTemplate是Spring提供的用於訪問Rest服務的客戶端,java
RestTemplate提供了多種便捷訪問遠程Http服務的方法,可以大大提升客戶端的編寫效率。web
調用RestTemplate的默認構造函數,RestTemplate對象在底層經過使用java.net包下的實現建立HTTP 請求,spring
能夠經過使用ClientHttpRequestFactory指定不一樣的HTTP請求方式。apache
ClientHttpRequestFactory接口主要提供了兩種實現方式api
一、一種是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)建立底層的Http請求鏈接。springboot
二、一種方式是使用HttpComponentsClientHttpRequestFactory方式,底層使用HttpClient訪問遠程的Http服務,使用HttpClient能夠配置鏈接池和證書等信息。網絡
@Configuration class RestTemplateConfig { /** * 構建一個使用默認配置RestTemplate Bean */ @Bean fun restTemplate():RestTemplate { return RestTemplateBuilder().build() } }
@Component class RestTemplateClient { @Autowired lateinit var restTemplate: RestTemplate val logger:Logger = LoggerFactory.getLogger(this.javaClass) /** * 發送POST請求,經過Form表單提交參數 */ fun <T> postForm(params: Map<String, String>, url: String, t:T) : ResultDTO<T>? { logger.info("請求URL===========:{}", url) logger.info("請求參數===========:{}", params) val httpHeaders = HttpHeaders() httpHeaders.contentType = MediaType.APPLICATION_FORM_URLENCODED val requestParams = LinkedMultiValueMap<String, String>() params.forEach(requestParams::add) val httpEntity = HttpEntity<MultiValueMap<String, String>>(requestParams, httpHeaders) return restTemplate.postForObject(url, httpEntity, ResultDTO<T>().javaClass) } }
@RestController @RequestMapping("/api") class LotteryController { @Autowired lateinit var restTemplateClient: RestTemplateClient /** * 彩票類型查詢 */ @PostMapping("/lottery/types") fun lotteryTypes(@RequestBody params:Map<String, String>) : ResultDTO<LotteryDTO>? { return restTemplateClient.postForm(params, UrlEnums.DEMO1.url, LotteryDTO()) } }
/** * 發送POST請求,經過Form表單提交參數 */ fun <T> postBody(params: Map<String, String>, url: String, t:T) : ResultDTO<T>? { logger.info("請求URL===========:{}", url) logger.info("請求參數===========:{}", params) val httpHeaders = HttpHeaders() httpHeaders.contentType = MediaType.APPLICATION_JSON_UTF8 val httpEntity = HttpEntity(params, httpHeaders) return restTemplate.postForObject(url, httpEntity, ResultDTO<T>().javaClass) }
/** * 發送POST請求,經過Form表單提交參數 */ fun <T> get(params: Map<String, String>, url: String, t:T) : ResultDTO<T>? { logger.info("請求URL===========:{}", url) logger.info("請求參數===========:{}", params) val builder = StringBuilder() params.forEach{k, v -> builder.append(k).append("=").append(v).append("&") } val param : String = builder.toString().substring(0, builder.length - 1) return restTemplate.getForObject(url.plus(param), ResultDTO<T>().javaClass) }
/** * 下載資源 */ fun downGet(url: String, headerParams: Map<String, String>) : ByteArray? { logger.info("資源URL==========>:{}", url) val httpHeaders = HttpHeaders() if (!CollectionUtils.isEmpty(headerParams)) { headerParams.forEach(httpHeaders::add) } val httpEntity = HttpEntity(LinkedMultiValueMap<String, String>().putAll(httpHeaders)) return restTemplate.exchange(url, HttpMethod.GET, httpEntity, ByteArray::class.java).body }
咱們在開發微服務應用的時候,有時候一個應用可能會部署不少臺,並且仍是不在不通的機器上,這個時候咱們能夠用Nginx作一個負載均衡,可是咱們這裏推薦使用的是SpringCloud提供的負載均衡,只要在Bean
上面加一個註解便可@LoadBalanced
,以下所示:app
@Bean @LoadBalanced fun restTemplate():RestTemplate { return RestTemplateBuilder().build() }
和調用普通的http請求有點不一樣的地方是,調用微服務是http://application.name/xxx
,咱們訪問的路徑是微服務應用名稱+業務路由
,由於服務會註冊到註冊中心,註冊中心會維護這個應用名稱,當咱們經過應用去訪問時,就能夠知道這個應用在那臺機器上了。負載均衡
基礎使用講完了,可是這裏還存在一個問題,由於咱們使用的是最簡單的配置,在這裏咱們沒有設置默認超時時間,官方默認的是60S,可是咱們業務中一般對響應速度是有要求,一分鐘的等待時間對於用戶來講太長了,這個時候咱們就須要有一個超時機制,具體的設置以下:框架
package io.intodream.kotlin05.config import org.apache.http.impl.client.HttpClientBuilder import org.springframework.beans.factory.annotation.Value import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.web.client.RestTemplateBuilder 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.client.SimpleClientHttpRequestFactory import org.springframework.http.converter.HttpMessageConverter import org.springframework.http.converter.StringHttpMessageConverter import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate import java.nio.charset.StandardCharsets /** * @description * RestTemplate 配置 * @author Jwenk * @copyright intoDream.io 築夢科技 * @email xmsjgzs@163.com * @date 2019-04-05,22:42 */ @Configuration class RestTemplateConfig { @Value("\${remote.maxTotalConnect}") val maxTotalConnect: Int = 0 @Value("\${remote.maxConnectPerRoute}") val maxConnectPerRoute: Int = 200 @Value("\${remote.connectTimeout}") val connectTimeout: Int = 2000 @Value("\${remote.readTimeout}") val readTimeout: Int = 3000 /** * 建立HTTP客戶端工廠 */ private fun createFactory() : ClientHttpRequestFactory { if (this.maxTotalConnect <= 0) { val factory = SimpleClientHttpRequestFactory() factory.setReadTimeout(this.readTimeout) factory.setConnectTimeout(this.connectTimeout) return factory } val httpClient = HttpClientBuilder.create() .setMaxConnTotal(this.maxTotalConnect) .setMaxConnPerRoute(this.maxConnectPerRoute).build() val factory = HttpComponentsClientHttpRequestFactory(httpClient) factory.setConnectTimeout(this.connectTimeout) factory.setReadTimeout(this.readTimeout) return factory } /** * 構建一個使用默認配置RestTemplate Bean */ @Bean fun restTemplate():RestTemplate { val restTemplate = RestTemplate(this.createFactory()) val converterList : MutableList<HttpMessageConverter<*>> = restTemplate.messageConverters var converterTarget : HttpMessageConverter<*>? = null /** * 從新設置StringHttpMessageConverter字符集爲UTF-8,解決中文亂碼問題 */ for (item: HttpMessageConverter<*> in converterList) { if (StringHttpMessageConverter::class.java == item.javaClass) { converterTarget = item break } } if (null != converterTarget) { converterList.remove(converterTarget) } converterList.add(1, StringHttpMessageConverter(StandardCharsets.UTF_8)) return restTemplate } }
記得在pom.xml
裏面引入HttpClient
的jar,否則啓動會報錯的
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency>
關於RestTemplate的一些使用及配置優化到此就結束了,喜歡的朋友能夠關注本人的博客https://www.tisnz.com,若是有不對的地方歡迎指正。