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();
}
});
}
}
}
AsyncRequestCallbackAdapter源码
我觉得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();
}
}