1、RestTemplate 是什么?有何作用?使用场景?
RestTemplate 是spring-web 对rest规范的一个封装;它的作用就是:可以发起rest规范的请求;使用场景:凡是你在代码中需要发起http请求的地方都能使用。
2、RestTemplate的使用案例:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<OrderDto> forEntity = restTemplate.getForEntity("http://localhost:8080/getOrderById?orderId=" + orderId, OrderDto.class);
这是一个简单的get请求的案例,RestTemplate里面封装了rest规范的所有发起请求的方式,此处我们不在一 一列举,因为我们不是偏向使用,我们主要是来分析RestTemplate的原理的。
3、废话不多说,源码分析开始:
3.1、先看类图关系:
实现父类如下:
RestOperations : 顾名思义,这个接口就是定义了rest规范的操作集。
HttpAccessor:http存储器,这个听起来是不是很奇怪,之所以叫存储器,那是因为HttpAccessor这个类能够创建Http请求实例ClientHttpRequest出来,所以就叫Http存储器。
InterceptingHttpAccessor : 拦截器存储器,里面存放的是http请求的拦截器列表。
3.2、HttpAccessorhttp存储器源码分析:作用使用其成员属性ClientHttpRequestFactory requestFactory创建客户端http请求实例ClientHttpRequest
public abstract class HttpAccessor {
protected final Log logger = HttpLogging.forLogName(getClass());
客户端请求工厂,用于创建客户端http请求实例ClientHttpRequest,默认是SimpleClientHttpRequestFactory,可以进行替换,例如切换为apache httpclient、okhttp都可以。
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
客户端http请求初始者列表,用于初始化创建好的客户端http请求。
private final List<ClientHttpRequestInitializer> clientHttpRequestInitializers = new ArrayList<>();
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
this.requestFactory = requestFactory;
}
public ClientHttpRequestFactory getRequestFactory() {
return this.requestFactory;
}
public void setClientHttpRequestInitializers(
List<ClientHttpRequestInitializer> clientHttpRequestInitializers) {
if (this.clientHttpRequestInitializers != clientHttpRequestInitializers) {
this.clientHttpRequestInitializers.clear();
this.clientHttpRequestInitializers.addAll(clientHttpRequestInitializers);
AnnotationAwareOrderComparator.sort(this.clientHttpRequestInitializers);
}
}
public List<ClientHttpRequestInitializer> getClientHttpRequestInitializers() {
return this.clientHttpRequestInitializers;
}
创建客户端http请求且使用初始化者进行初始化
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
initialize(request);
if (logger.isDebugEnabled()) {
logger.debug("HTTP " + method.name() + " " + url);
}
return request;
}
private void initialize(ClientHttpRequest request) {
this.clientHttpRequestInitializers.forEach(initializer -> initializer.initialize(request));
}
}
ClientHttpRequestFactory接口类图:
在上面类图中我们没有对RibbonClientHttpRequestFactory进行说明,原因是RibbonClientHttpRequestFactory 这个客户端请求工厂它是使用了Netflix的RestClient来进行http请求的发起与响应的处理的,其底层处理http请求与响应的http客户端是jersey。
InterceptingClientHttpRequestFactory只是一个包装了ClientHttpRequestFactory + interceptors的包装器。
我们知道了ClientHttpRequestFactory是用来创建客户端http请求实例的ClientHttpRequest,其实ClientHttpRequest也是一个接口,接下来我们看看ClientHttpRequest的接口类图:
每一种ClientHttpRequestFactory创建的客户端请求实例类型关系:
SimpleClientHttpRequestFactory------------> SimpleBufferingClientHttpRequest(HttpURLConnection connection, boolean outputStreaming)
HttpComponentsClientHttpRequestFactory--------> HttpComponentsClientHttpRequest(HttpClient client, HttpUriRequest request, HttpContext context)
OkHttp3ClientHttpRequestFactory--------------> OkHttp3ClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method)
RibbonClientHttpRequestFactory---------> RibbonHttpRequest(URI uri, HttpRequest.Verb verb, RestClient client, IClientConfig config)
InterceptingClientHttpRequestFactory--------> InterceptingClientHttpRequest(ClientHttpRequestFactory chrf, List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method)
3.3、InterceptingHttpAccessor拦截器储存器源码分析
public abstract class InterceptingHttpAccessor extends HttpAccessor {
储存的拦截器,这些拦截器会在http请求被执行之前进行调用
private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
看见没这里立马就使用了有拦截功能的请求工厂,就是我们上面提到的InterceptingClientHttpRequestFactory
@Nullable
private volatile ClientHttpRequestFactory interceptingRequestFactory;
public级别的方法,因此可以设置拦截器列表
public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
Assert.noNullElements(interceptors, "'interceptors' must not contain null elements");
// Take getInterceptors() List as-is when passed in here
if (this.interceptors != interceptors) {
this.interceptors.clear();
this.interceptors.addAll(interceptors);
AnnotationAwareOrderComparator.sort(this.interceptors);
}
}
public List<ClientHttpRequestInterceptor> getInterceptors() {
return this.interceptors;
}
设置客户端http请求工厂,这里我们就能够替换掉RestTemplate底层的httpclient的类型,例如切换成okhttp3.
@Override
public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
调用父类的setRequestFactory方法,父类是谁,不就是HttpAccessor吗,那这样的话
HttpAccessor中的requestFactory = 我们设置的了,不再是默认的new
SimpleClientHttpRequestFactory()了吧,这就起到了切换httpclient类型的效果。
super.setRequestFactory(requestFactory);
this.interceptingRequestFactory = null;
}
获取请求工厂,这个是核心方法!!!!!!!!!!!!!!!!
@Override
public ClientHttpRequestFactory getRequestFactory() {
1、先获取存储的拦截器列表
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
2、如果有拦截器那就构建一个带拦截功能的客户端http请求工厂InterceptingClientHttpRequestFactory实例返回。
if (!CollectionUtils.isEmpty(interceptors)) {
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
if (factory == null) {
factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
3、如果没有拦截器那就直接获取父类HttpAccessor中的客户端http请求工厂实例返回。
else {
return super.getRequestFactory();
}
}
}
3.4、最终的实现类RestTemplate源码解析:
上面我们把 RestTemplate 的父类 InterceptingHttpAccessor 以及 InterceptingHttpAccessor 的父类 HttpAccessor 进行了剖析,下面我们来剖析最终的实现类 RestTemplate;
3.4.1、RestTemplate 的核心属性:
Ⅰ: List<HttpMessageConverter<?>> messageConverters:消息转换器列表,在 springmvc 中这个应该不陌生。
Ⅱ: ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler(); :响应错误处理器。
Ⅲ: ResponseExtractor<HttpHeaders> headersExtractor = new HeadersExtractor(); :响应头提取器。
Ⅳ:继承父类 HttpAccessor 的属性 ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory() :http 请求构建工厂。
Ⅴ:继承父类 InterceptingHttpAccessor 的属性private final List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>() :拦截器列表,这个是很重要的东西,在spring-cloud-netflix-ribbon中就是使用了拦截器进行负载均衡处理的。
3.4.2、RestTemplate 核心属性的设置方式:
方式1:set函数:
restTemplate.setErrorHandler(ResponseErrorHandler errorHandler);
restTemplate.setMessageConverters(List<HttpMessageConverter<?>> messageConverters);
restTemplate.setRequestFactory(ClientHttpRequestFactory requestFactory);
restTemplate.setInterceptors(List<ClientHttpRequestInterceptor> interceptors);
方式2: 构造函数, 默认的无参数构造函数会自动设置一些常用的 HttpMessageConverter 列表;
这个构造函数可以设置ClientHttpRequestFactory属性,因此可以设置为okhttp、apache httpComponentClient等客户端。
public RestTemplate(ClientHttpRequestFactory requestFactory) {
this();
setRequestFactory(requestFactory);
}
这个构造函数可以设置入参HttpMessageConverter列表,拦截器的顺序可以使用@Order注解,或者实现Ordered接口来进行定义。
public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {
validateConverters(messageConverters);
this.messageConverters.addAll(messageConverters);
this.uriTemplateHandler = initUriTemplateHandler();
}
3.4.3、RestTemplate执行流程的解析;
案例1:无拦截器案例
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<OrderDto> forEntity = restTemplate.getForEntity("http://localhost:8080/getOrderById?orderId=" + orderId, OrderDto.class);
第1步:RestTemplate.getForEntity(String url, Class<T> responseType, Object... uriVariables);
@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
}
第2步:RestTemplate.execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables);
@Override
@Nullable
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
获取url模板处理器进行url的处理,例如GET请求的参数替换。
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
第3步:RestTemplate.doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor);
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
1、创建一个请求,此处就会调用父类HttpAccessor的createRequest方法。
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
2、执行请求。
response = request.execute();
3、处理响应
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
父类HttpAccessor的createRequest(URI url, HttpMethod method)实现:
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
先获取客户端http请求工厂,然后使用请求工厂创建客户端http请求实例,
在我们当前的案例中requestFactory = new SimpleClientHttpRequestFactory()的,因此创建的客户端
请求实例就是SimpleBufferingClientHttpRequest(connection, this.outputStreaming)实例,jdk的
HttpURLConnection来进行请求发送,在创建SimpleClientHttpRequestFactory的createRequest方法中会
先openConnection也就是打开连接,然后使用连接构建SimpleBufferingClientHttpRequest返回。
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
初始化客户端http请求实例
initialize(request);
if (logger.isDebugEnabled()) {
logger.debug("HTTP " + method.name() + " " + url);
}
返回客户端http请求实例
return request;
}
SimpleBufferingClientHttpRequest的execute()方法实现:
首先执行一级父类AbstractClientHttpRequest的execute()方法:
@Override
public final ClientHttpResponse execute() throws IOException {
assertNotExecuted();
执行内部的执行函数
ClientHttpResponse result = executeInternal(this.headers);
this.executed = true;
return result;
}
接着来到二级父类AbstractBufferingClientHttpRequestexecuteInternal(..):
@Override
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
byte[] bytes = this.bufferedOutput.toByteArray();
if (headers.getContentLength() < 0) {
headers.setContentLength(bytes.length);
}
ClientHttpResponse result = executeInternal(headers, bytes);
this.bufferedOutput = new ByteArrayOutputStream(0);
return result;
}
最终执行到SimpleBufferingClientHttpRequest的executeInternal(...):
protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
addHeaders(this.connection, headers);
// JDK <1.8 doesn't support getOutputStream with HTTP DELETE
if (getMethod() == HttpMethod.DELETE && bufferedOutput.length == 0) {
this.connection.setDoOutput(false);
}
if (this.connection.getDoOutput() && this.outputStreaming) {
this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
}
发起http请求
this.connection.connect();
if (this.connection.getDoOutput()) {
FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
}
else {
// Immediately trigger the request in a no-output scenario as well
this.connection.getResponseCode();
}
return new SimpleClientHttpResponse(this.connection);
}
案例2:有拦截器案例
@Order(0)
@Component
public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
System.out.println("call MyClientHttpRequestInterceptor intercept . . .");
execution.execute(request, body);
return null;
}
}
@Bean
public RestTemplate restTemplate(MyClientHttpRequestInterceptor myClientHttpRequestInterceptor){
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> intercepters = new ArrayList <>();
intercepters.add(myClientHttpRequestInterceptor);
restTemplate.setInterceptors(intercepters);
return restTemplate;
}
@Autowired
private RestTemplate restTemplate;
@GetMapping("userGetOrderById")
public OrderDto userGetOrderById(@RequestParam("orderId") String orderId){
ResponseEntity<OrderDto> forEntity = restTemplate.getForEntity("http://localhost:8080/getOrderById?orderId=" + orderId, OrderDto.class);
return forEntity.getBody();
}
跟没有拦截器的唯一的区别就在于RestTemplate.doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor)这个方法中的依据代码:ClientHttpRequest request = createRequest(url, method); 就会调用父类HttpAccessor的createRequest(URI url, HttpMethod method)方法,源码如下:
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
在当前的HttpAccessor类中有一个getRequestFactory(),然而在子类
InterceptingHttpAccessor中复写了这个方法,那么就会来到子类InterceptingHttpAccessor中
ClientHttpRequest request = getRequestFactory().createRequest(url, method);
initialize(request);
if (logger.isDebugEnabled()) {
logger.debug("HTTP " + method.name() + " " + url);
}
return request;
}
子类InterceptingHttpAccessor中的 getRequestFactory()实现如下:
@Override
public ClientHttpRequestFactory getRequestFactory() {
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
如果存在拦截器,那就构建一个InterceptingClientHttpRequestFactory类型的客户端请
求工厂,我们都知道InterceptingClientHttpRequestFactory只是一个包装,因此会使用父类
HttpAccessor的requestFactory来构建InterceptingClientHttpRequestFactory实例。
if (!CollectionUtils.isEmpty(interceptors)) {
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
if (factory == null) {
factory = new
InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
else {
return super.getRequestFactory();
}
}
我们在上面提及到过InterceptingClientHttpRequestFactory创建的请求类型是InterceptingClientHttpRequest,InterceptingClientHttpRequestFactory源码如下:
public class InterceptingClientHttpRequestFactory extends AbstractClientHttpRequestFactoryWrapper {
private final List<ClientHttpRequestInterceptor> interceptors;
public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory,
@Nullable List<ClientHttpRequestInterceptor> interceptors) {
super(requestFactory);
this.interceptors = (interceptors != null ? interceptors : Collections.emptyList());
}
创建InterceptingClientHttpRequest请求实例
@Override
protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
}
}
InterceptingClientHttpRequest请求源码如下:
class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {
private final ClientHttpRequestFactory requestFactory;
private final List<ClientHttpRequestInterceptor> interceptors;
private HttpMethod method;
private URI uri;
protected InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory,
List<ClientHttpRequestInterceptor> interceptors, URI uri, HttpMethod method) {
this.requestFactory = requestFactory;
this.interceptors = interceptors;
this.method = method;
this.uri = uri;
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
public String getMethodValue() {
return this.method.name();
}
@Override
public URI getURI() {
return this.uri;
}
最终执行父类的execute后会调用到此处的executeInternal方法
@Override
protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
创建一个拦截器请求执行器实例,拦截器请求执行器类是当前类的内部类
InterceptingRequestExecution requestExecution = new InterceptingRequestExecution();
使用拦截器请求执行器实例执行当前请求
return requestExecution.execute(this, bufferedOutput);
}
拦截器请求执行器类
private class InterceptingRequestExecution implements ClientHttpRequestExecution {
private final Iterator<ClientHttpRequestInterceptor> iterator;
public InterceptingRequestExecution() {
this.iterator = interceptors.iterator();
}
@Override
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
来到拦截器请求执行器类的执行方法,第一步就是循环执行所有的拦截器
if (this.iterator.hasNext()) {
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
return nextInterceptor.intercept(request, body, this);
}
所有的拦截器执行完成后开始执行http请求的发起与处理响应
else {
HttpMethod method = request.getMethod();
Assert.state(method != null, "No standard HTTP method");
当前的拦截器请求实例InterceptingClientHttpRequest只是一个包装,因此还需要使用HttpAccessor的requestFactory来创建真正的客户端http请求实例。
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), method);
request.getHeaders().forEach((key, value) -> delegate.getHeaders().addAll(key, value));
if (body.length > 0) {
if (delegate instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
streamingOutputMessage.setBody(outputStream -> StreamUtils.copy(body, outputStream));
}
else {
StreamUtils.copy(body, delegate.getBody());
}
}
使用真正的客户端http请求实例发起http请求。
return delegate.execute();
}
}
}
}
以上就是RestTemplate的原理剖析,之所以来剖析RestTemplate的原理,就是为了后面学习spring-cloud-netfliux-ribbon打基础。