91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用RestTemplate

發布時間:2021-10-23 14:45:56 來源:億速云 閱讀:135 作者:iii 欄目:開發技術

本篇內容介紹了“如何使用RestTemplate”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一、概述

本文主要介紹 Spring Web 模塊中的 RestTemplate 組件的原理、優缺點、以及如何擴展以滿足各種需求。

在介紹 RestTemplate 之前,我們先來談談 HTTP Client,談談選擇一個優秀的 HTTP Client 實現的的重要性,以及一個優秀的 HTTP Client 應該具備哪些特性。

在 Java 社區中,HTTP Client 主要有 JDK 的 HttpURLConnection、Apache Commons HttpClient(或被稱為 Apache HttpClient 3.x)、Apache HttpComponents Client(或被稱為 Apache HttpClient 4.x)、Square 公司開源的 OkHttp。

除了這幾個純粹的 HTTP Client 類庫以外,還有 Spring 的 RestTemplate、Square 公司的 Retrofit、Netflix 公司的 Feign,以及像 Apache CXF 中的 client 組件。這些框架和類庫主要是針對 Web Service 場景,尤其是 RESTful Web Service。它們往往是基于前面提到的 HTTP Client 實現,并在其基礎上提供了消息轉換、參數映射等對于 Web Service 來說十分必要的功能。

(當然,像 Netty、Mina 這樣的網絡 IO 框架,實現 HTTP 自然也不再話下,但這些框架通常過于底層,不會被直接使用)

選擇一個優秀的 HTTP Client 的重要性

雖然現在服務間的調用越來越多地使用了 RPC 和消息隊列,但是 HTTP 依然有適合它的場景。

RPC 的優勢在于高效的網絡傳輸模型(常使用 NIO 來實現),以及針對服務調用場景專門設計協議和高效的序列化技術。而 HTTP 的優勢在于它的成熟穩定、使用實現簡單、被廣泛支持、兼容性良好、防火墻友好、消息的可讀性高。所以在開放 API、跨平臺的服務間調用、對性能要求不苛刻的場景中有著廣泛的使用。

正式因為 HTTP 存在著很廣泛的應用場景,所以選擇一個優秀的 HTTP Client 便是十分重要的。

優秀的 HTTP Client 需要具備的特性

  • 連接池

  • 超時時間設置(連接超時、讀取超時等)

  • 是否支持異步

  • 請求和響應的編解碼

  • 可擴展性

連接池

因為目前 HTTP 1.1 不支持多路復用,只有 HTTP Pipeline 這用半復用的模型支持。所以,在需要頻繁發送消息的場景中,連接池使必須支持的,以減少頻繁建立連接所帶來的不必要的性能損耗。

超時時間設置(連接超時、讀取超時等)

當對端出現問題的時候,長時間的,甚至是無限的超時等待是絕對不能接受的。所以必須必須能夠設置超時時間。

是否支持異步

HTTP 相關技術(服務器端和客戶端)通常被人認為是性能低下的一個重要原因在于,在很長一段時間里,HTTP 的相關實現缺乏對異步的支持。這不僅指非阻塞 IO,也包括異步的編程模型。缺乏異步編程模型的后果就是,即便 HTTP 協議棧是基于非阻塞 IO 實現的,調用客戶端的或者在服務端處理消息的線程有大量時間被浪費在了等待 IO 上面。所以,異步是非常重要的特性。

請求和響應的編解碼

通常,開發人員希望面向對象使用各種服務(這里面自然也包括基于 HTTP 協議的服務),而不是直接面對原始的消息和響應開發。所以,透明地將 HTTP 請求和響應進行編解碼是十分有必要,因為這可以很大程度地降低開發人員的工作量。

可擴展性

不論一個框架設計的多好,總有一些特殊場景是它們無法原生支持的。這時可擴展性的好壞便體現出來了。

答案

基于上述幾點的考慮,RestTemplate 是相對好的選擇。原因在于 RestTemplate 本身基于成熟的 HTTP Client 實現(Apache HttpClient、OkHttp 等),并可以靈活地在這些實現中切換,而且具有良好的擴展性。最重要的是提供了前面幾個 HTTP Client 不具備的消息編解碼能力。

這里要提一句為什么沒有自己封裝 HTTP Client 的原因。這個原因在于想要基于一種 HTTP Client 去提供消息編解碼能力和一定的擴展能力并不難,但是如果要設計出一個通用的,對底層實現透明的,具有優秀如 Spring 的擴展性設計的框架并不是一件容易事。這里的不易并不在于技術有多高深,而是在于優秀的擴展性設計往往源自從眾多優秀程序員、社區和軟件公司得到的豐富的一線實踐經驗,再由像 Spring 轉換為最終設計。這樣的產品不是一朝一夕就能得到的。在我們覺得自己打造自己的工具之前,我們可以先深入了解現有的優秀功能都能做到什么。

二、使用 RestTemplate 的缺點

欲揚先抑,我們先來看加入使用 RestTemplate,可能會遇到哪些“坑”。

依賴 Spring 其它模塊

雖然 spring-web 模塊對其它 Spring 模塊并沒有顯式的依賴(Maven dependency 的 scope 為 compile),但是對于一些功能,比如異步版本的 RestTemplate,要求必須有 4.1 以上版本的 spring-core 模塊。

所以,要想 RestTemplate 完全發揮其功能,最好能有相近版本的其它的 Spring 模塊相配合(spring-core、spring-context、spring-beans、spring-aop)

默認情況下 RestTemplate 存在的不足

Spring Web 模塊中的 RestTemplate 是一個很不錯的面向 RESTful Web 服務的客戶端。它提供了很多簡化對 RESTful Web 服務調用的功能,例如 Path Parameter 的格式化功能(/hotels/{hotel_id}/books/{book_id},這里的 hotel_id 和 book_id 就是 Path Paramter)、JSON 或 XML 等格式的數據與實體類之間的透明轉換等。

所謂默認情況指的是不去擴展 RestTemplate 所提供的類或接口,而是完全依賴其本身提供的代碼。在這種情況下,RestTemplate 還是有一些不便的地方。例如,它的 Path Parameter 格式化功能,對于普通 HTTP 服務的調用來說,反而成為了一個缺點,因為普通的 HTTP 服務的 GET 方法常使用 Query Parameter,而不是 Path Parameter。Query Paramter 的形式是 an_http_url?name1=value1&name2=value2。例如 getOrder.action?order_code=xxx。如果使用 RestTemplate,作為參數傳遞給 RestTemplate 的 URL 就必須是 getOrder.action?order_code={order_code}。如果是固定的參數還好,如果一個 HTTP 服務的 Query Parameter 是可變的,那就很不方便了。

三、擴展 RestTemplate

注意,下面涉及到的代碼都是基于 spring-web 4.2.6.RELEASE 版本

設置 Query Params

上面提到,RestTemplate 的 getForEntity、getForObject、postForEntity 等方法中的 Map 參數是 uriVariables,即我們常說的 Path Param,而非 Query Param(這兩個參數的定義可以參照 JAX-RS 中 @PathParam 和 @QueryParam 的定義)。

Path Param 是 URL 的一部分,RESTful 的 Web Service 會按照其定義的 URL Template 從 URL 中解析出其對應的值

RestTemplate 的這種機制面對 RESTful 的 Web Service 無疑是方便的,但很多情況下我們還是希望 RestTemplate 能夠在開發人員不用編寫額外代碼的情況下將 Map 類型的參數當做 Query Param 發送給對端的服務。

幸好來自 Spring 大家庭的 RestTemplate 也具有良好的可擴展性,其具有一個名為 UriTemplateHandler 擴展點。因為不論是 Path Param 還是 Query Param,它們都是 URI 的一部分,所以只需實現自定義的 URI 生成機制即可解決這個問題。

通過擴展 DefaultUriTemplateHandler,我們可以將 Map<String, ?> uriVariables 也作為 Query Param。具體實現如下:

public class QueryParamsUrlTemplateHandler extends DefaultUriTemplateHandler {
    @Override
    public URI expand(String uriTemplate, Map<String, ?> uriVariables) {
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(uriTemplate);
        for (Map.Entry<String, ?> varEntry : uriVariables.entrySet()) {
            uriComponentsBuilder.queryParam(varEntry.getKey(), varEntry.getValue());
        }
        uriTemplate = uriComponentsBuilder.build().toUriString();
        return super.expand(uriTemplate, uriVariables);
    }
}

上面的實現基于 DefaultUriTemplateHandler,所以保有了原來設置 Path Param 的功能。

設置自定義的 HTTP Header

實現這個需求有多種方法,比如通過攔截器。這里使用另一個方法,通過一個自定義的 ClientHttpRequestFactory

public class CustomHeadersClientHttpRequestFactoryWrapper extends AbstractClientHttpRequestFactoryWrapper {
    private HttpHeaders customHeaders = new HttpHeaders();
    /**
     * Create a {@code AbstractClientHttpRequestFactoryWrapper} wrapping the given request factory.
     *
     * @param requestFactory the request factory to be wrapped
     */
    protected CustomHeadersClientHttpRequestFactoryWrapper(ClientHttpRequestFactory requestFactory) {
        super(requestFactory);
    }
    @Override
    protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod,
            ClientHttpRequestFactory requestFactory) throws IOException {
        ClientHttpRequest request = requestFactory.createRequest(uri, httpMethod);
        for (Map.Entry<String, List<String>> headerEntry : customHeaders.entrySet()) {
            request.getHeaders().put(headerEntry.getKey(), headerEntry.getValue());
        }
        return request;
    }
    public void addHeader(String header, String... values) {
        customHeaders.put(header, Arrays.asList(values));
    }
}

簡化配置

RestTemplate 提供了良好的擴展性,但是有些設置是使用 ``

四、RestTemplate 原理解析

HTTP Client 實現

RestTemplate 本身并沒有做 HTTP 底層的實現,而是利用了現有的技術,如 JDK 或 Apache HttpClient 等。

RestTemplate 需要使用一個實現了 ClientHttpRequestFactory 接口的類為其提供 ClientHttpRequest 實現(另外還有 AsyncClientHttpRequestFactory 對應于異步 HTTP 實現,這里暫且不表)。而 ClientHttpRequest 則實現封裝了組裝、發送 HTTP 消息,以及解析響應的的底層細節。

目前(4.2.6.RELEASE)的 RestTemplate 主要有四種 ClientHttpRequestFactory 的實現,它們分別是:

  • 基于 JDK HttpURLConnection 的 SimpleClientHttpRequestFactory

  • 基于 Apache HttpComponents Client 的 HttpComponentsClientHttpRequestFactory

  • 基于 OkHttp 2(OkHttp 最新版本為 3,有較大改動,包名有變動,不和老版本兼容)的 OkHttpClientHttpRequestFactory

  • 基于 Netty4 的 Netty4ClientHttpRequestFactory

另外,還有用于提供攔截器功能的 InterceptingClientHttpRequestFactory。

寫消息

寫消息指的是 requestBody 轉換為某一種格式,如 JSON、XML 的數據的過程。

spring-web 模塊提供了一個 HttpMessageConverter 接口,用來讀寫 HTTP 消息。這個接口不僅被 RestTemplate 使用,也被 Spring MVC 所使用。

spring-web 模塊提供了基于 Jackson、GSON 等類庫的 HttpMessageConverter,用于進行 JSON 或 XML 格式數據的轉換。

RestTemplate 在發送消息時,會根據消息的 ContentType 或者 RequestBody 對象本身的一些屬性判斷究竟是使用哪個 HttpMessageConverter 寫消息。

具體來說,如果 RequestBody 是一個 HttpEntity 的話,會從中讀取 ContentType 屬性。同時,RequestBody 對象本身也會覺得一個 HttpMessageConverter 是否會處理這個對象。例如,ProtobufHttpMessageConverter 會要求 RequestBody 對象必須實現 com.google.protobuf.Message 接口。

讀消息

讀消息指的是讀取 HTTP Response 中的數據,轉換為用戶指定的格式(通過 Class<T> responseType 參數指定)。類似于寫消息的處理,讀消息的處理也是通過 ContentType 和 responseType 來選擇的相應 HttpMessageConverter 來進行的。

錯誤處理

RestTemplate 提供了一個 ResponseErrorHandler 的接口,用來處理錯誤的 Response。可以通過設置自定義的 ResponseErrorHandler 來實現擴展。

后記

根據我上面表達的思想,一個統一、規范和簡化 RestTemplate 使用的工具已經產生,不過暫時由于其代碼是公司項目的一部分,所以暫時不便公開。而且我希望是在這個工具經過了更多的實踐考驗之后再貢獻出來會更好。

目前的一個完整使用案例如下:

@Configuration
public class SpringConfigurationDemo {
    @Bean
    public RestTemplate myRestTemplate() {
        return RestTemplateBuilder.create()
                .withClientKey("myRestTemplate")
                .implementation(HttpClientImplementation.OK_HTTP)
                .clearMessageConverters()
                .setMessageConverter(new MappingJackson2HttpMessageConverter(), MediaType.TEXT_PLAIN)
                .enableAutoQueryParams()
                .connectTimeout(100)
                .readTimeout(200)
                .header(HttpHeaders.USER_AGENT, "MyAgent")
                .build();
    }
}

雖然 RestTemplate 是一個很不錯的 HTTP Client,但 Netflix 已經開源了一個更好地 HTTP Client 工具 - Feign。它是一個聲明式的 HTTP Client,在易用性、可讀性等方面大幅領先于現有的工具。我打算稍后寫一篇文章分析 Feign 的思想、原理和優點(原理其實不復雜,但是能想到這么做的卻沒幾個,原創的創新思想永遠是最可貴的)

“如何使用RestTemplate”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

昆山市| 肥西县| 汾阳市| 汝州市| 汽车| 佳木斯市| 无棣县| 隆安县| 苍山县| 乐安县| 潢川县| 大宁县| 普安县| 隆安县| 江源县| 彭水| 长顺县| 肇州县| 白水县| 盱眙县| 容城县| 怀化市| 区。| 石家庄市| 永兴县| 铜梁县| 蓝田县| 句容市| 巴林右旗| 武陟县| 凤山县| 福海县| 湟中县| 建平县| 五原县| 松阳县| 神池县| 肃宁县| 南涧| 潼南县| 望江县|