【Spring-web】AsyncRestTemplate源碼學習

2017-01-23 by 安靜的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/6343347.htmlhtml

 

本篇概要

 

類說明

AsyncRestTemplate 是 Spring中提供異步的客戶端HTTP訪問的核心類。與RestTemplate類類似,它提供了一些相似的方法,只不過返回類型不是具體的結果,而是ListenableFuture包裝類。
 
經過getRestOperations()方法,對外提供了一個同步的RestTemplate對象,而且經過這個RestTemplate對象來共享錯誤處理和消息轉換。
 
注意:默認狀況下,AsyncRestTemplate依靠標準JDK工具來建立HTTP連接。經過使用構造函數來接收AsyncClientHttpRequestFactory接口的具體實現類對象,你能夠選用不一樣的HTTP庫,例如Apache HttpComponents,Netty,以及OkHttp。
* Spring's central class for asynchronous client-side HTTP access. Exposes similar methods as RestTemplate, but returns ListenableFuture wrappers as opposed to concrete results.
The AsyncRestTemplate exposes a synchronous RestTemplate via the getRestOperations() method and shares its error handler and message converters with that RestTemplate.
Note: by default AsyncRestTemplate relies on standard JDK facilities to establish HTTP connections. You can switch to use a different HTTP library such as Apache HttpComponents, Netty, and OkHttp by using a constructor accepting an AsyncClientHttpRequestFactory.
 

類圖

類圖中省略了一些參數類型及重載的方法,在不影響理解的狀況下,保證各要素在一幅圖中展示。設計模式

 
 

 

簡單例子

    private String result = "";

    @Test
    public void testAsyncPost() throws Exception {
        String posturl = "http://xxxxxx";
        String params = "xxxxxx";
        
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
        headers.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        
        HttpEntity<Object> hpEntity = new HttpEntity<Object>(params, headers);
        AsyncRestTemplate asyncRt = new AsyncRestTemplate();
        
        ListenableFuture<ResponseEntity<String>> future = asyncRt.postForEntity(posturl, hpEntity, String.class);
        
        future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
            public void onSuccess(ResponseEntity<String> resp) {
                result = resp.getBody();
            }
            public void onFailure(Throwable t) {
                System.out.println(t.getMessage());
            }
        });
        System.out.println(result);
    }

 

精闢的內部類

    /**
     * Adapts a {@link RequestCallback} to the {@link AsyncRequestCallback} interface.
     */
    private static class AsyncRequestCallbackAdapter implements AsyncRequestCallback {

        private final RequestCallback adaptee;

        /**
         * Create a new {@code AsyncRequestCallbackAdapter} from the given
         * {@link RequestCallback}.
         * @param requestCallback the callback to base this adapter on
         */
        public AsyncRequestCallbackAdapter(RequestCallback requestCallback) {
            this.adaptee = requestCallback;
        }

        @Override
        public void doWithRequest(final AsyncClientHttpRequest request) throws IOException {
            if (this.adaptee != null) {
                this.adaptee.doWithRequest(new ClientHttpRequest() {
                    @Override
                    public ClientHttpResponse execute() throws IOException {
                        throw new UnsupportedOperationException("execute not supported");
                    }
                    @Override
                    public OutputStream getBody() throws IOException {
                        return request.getBody();
                    }
                    @Override
                    public HttpMethod getMethod() {
                        return request.getMethod();
                    }
                    @Override
                    public URI getURI() {
                        return request.getURI();
                    }
                    @Override
                    public HttpHeaders getHeaders() {
                        return request.getHeaders();
                    }
                });
            }
        }
    }
AsyncRequestCallbackAdapter源碼
 
我以爲AsyncRestTemplate類巧妙之處就在於複用了RestTemplate類,而最精闢之處就是AsyncRequestCallbackAdapter內部類(名字太長,下文簡稱Adapter)。從這個內部類的名字就能夠知道,此處使用了適配器設計模式。適配器模式的設計意圖就是在兩個不兼容的接口之間創建起溝通的橋樑。

那麼,這裏是如何將兩個類鏈接起來的呢?答案關鍵在於匿名類的使用。app

Adapter類中的成員變量adaptee,實際上引用的是RestTemplate中的*RequestCallback內部類對象。
Adapter.doWithRequest方法的參數類型是AsyncClientHttpRequest,而*RequestCallback.doWithRequest方法的參數類型是ClientHttpRequest。
經過建立匿名類對象,重寫接口方法,將各方法的返回指向AsyncClientHttpRequest參數對象。
在Adapter.doWithRequest方法中,以剛剛建立的匿名類對象做爲參數,直接調用*RequestCallback.doWithRequest方法。
這個匿名類對象就是兩個方法之間的橋樑。
 
平時工做中匿名類用的比較少,剛看這段源碼的時候真的有點蒙,接口怎麼能直接new一個對象了呢?忍不住開始懷疑人生-_-|||
baidu以後明白了,這不正是匿名類嘛~~~只不過它看起來像new了一個接口的對象,可是實際上編譯後會自動生成一個實現類。
 
其實,上面代碼寫成這樣↓↓↓就容易理解了。由此能夠看出,使用匿名類省略了一個實現類的定義和開銷。
    @Override
    public void doWithRequest(final AsyncClientHttpRequest request) throws IOException {
        if (this.adaptee != null) {
            this.adaptee.doWithRequest(new ClientHttpRequestImpl(request));
        }
    }
    private class ClientHttpRequestImpl implements ClientHttpRequest{
        
        private AsyncClientHttpRequest request;
        
        public ClientHttpRequestImpl(AsyncClientHttpRequest request){
            this.request = request;
        }
        @Override
        public ClientHttpResponse execute() throws IOException {
            throw new UnsupportedOperationException("execute not supported");
        }
        @Override
        public HttpMethod getMethod() {
            return request.getMethod();
        }
        @Override
        public URI getURI() {
            return request.getURI();
        }
        @Override
        public HttpHeaders getHeaders() {
            return request.getHeaders();
        }
        @Override
        public OutputStream getBody() throws IOException {
            return request.getBody();
        }
    }
返回頂部
相關文章
相關標籤/搜索