2017-01-23 by 安靜的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/6343347.html
本篇概要
類說明
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(); } }); } } }
我覺得AsyncRestTemplate類巧妙之處就在於復用了RestTemplate類,而最精辟之處就是AsyncRequestCallbackAdapter內部類(名字太長,下文簡稱Adapter)。從這個內部類的名字就可以知道,此處使用了適配器設計模式。適配器模式的設計意圖就是在兩個不兼容的接口之間建立起溝通的橋梁。
那么,這里是如何將兩個類連接起來的呢?答案關鍵在於匿名類的使用。
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(); } }