restTemplate源码解析(一)构造restTemplate的Bean实例
所有文章
https://www.cnblogs.com/lay2017/p/11740855.html
正文
构造一个restTemplate的Bean实例很容易,只需这样配置
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
但我们希望更多得了解一个这个构造过程做了哪些事情。为此,我们需要去打开restTemplate这个黑盒子。
restTemplate设计
先试着从restTemplate得类图上获得一些灵感,看看spring的作者是一个什么样的设计思路吧。

我们看到,简单的几个类和接口展示了标准的抽象设计。
HttpAccessor是一个抽象类,它抽象的是一个http访问器的概念。这说明,RestTemplate具备http方式请求响应的处理能力。再看RestOperations,它是一个接口,抽象的是restful风格的操作方法,这意味着RestTemplate的操作风格将是Restful的。
http访问器和restful风格操作做了一个分离。restTemplate则是聚合了两者,既有http访问器的基础能力,又在这个基础之上构建了restful风格。设计者把Restful操作作为接口,其实从规范角度上,我们应该面向RestOperations接口使用它。但大多数人似乎都直接使用RestTemplate,我们上面的代码示例也无意识地直接面向了RestTemplate这个实现类。
restTemplate实例构造过程
接下来,我们再看看new一个RestTemplate对象做了哪些事情。
进入RestTemplate类的构造方法
private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
private UriTemplateHandler uriTemplateHandler;
public RestTemplate() {
// 添加HttpMessageConverterjie
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter(false));
try {
this.messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Error err) {
// Ignore when no TransformerFactory implementation is available
}
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
this.messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
// uri模板处理器
this.uriTemplateHandler = initUriTemplateHandler();
}
构造方法有点长,但只做了两件事
1)添加HttpMessageConverter的实现类,熟悉springmvc的话估计知道HttpMessageConverter。顾名思义,它就是用来转换http请求响应过程中的消息数据的。
2)初始化一个UriTemplateHandler
我们跟进initUriTemplateHandler方法,看看怎么初始化一个uri模板处理器的
private static DefaultUriBuilderFactory initUriTemplateHandler() {
DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();
uriFactory.setEncodingMode(EncodingMode.URI_COMPONENT); // for backwards compatibility..
return uriFactory;
}
这里只是简单地构造了实例,并直接返回。由此可见,DefaultUriBuilderFactory应该直接或者间接实现了UriTemplateHandler
我们看看DefaultUriBuilderFactory的类图

与我们猜想的一样,DefaultUriBuilderFactory间接实现了UriTemplateHandler
RestTemplate的构造方法中就做了这两件事,我们再看看HttpAccessor
public abstract class HttpAccessor {
// ...
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
// ...
}
默认创建了一个ClientHttpRequestFactory的实例,ClientHttpRequestFactory这个接口是用来创建客户端的request请求对象的,我们并没有去自定义设置它默认采用SimpleClientHttpRequestFactory这个实现类。
ClientHttpRequestFactory作为工厂模式,将会生产ClientHttpRequest。ClientHttpRequest抽象了Http请求操作,执行ClientHttpRequest将会发送请求与服务端交互。
总结
到这里,RestTemplate的实例构造过程就结束了。其实它的原理就是封装了http请求操作而已。
我们再大体过一下RestTemplate的构造过程
1)在RestTemplate构造方法中添加了多个HttpMessageConverter后续用于http请求响应的数据转换
2)在RestTemplate构造方法中初始化了一个Uri模板的处理器,后续用于处理uri相关的东西
3)HttpAccessor默认创建了一个ClientHttpRequestFactory的成员实例,后续用于创建请求对象。
不过,似乎最有学习价值的还是一开始的restTemplate的设计图。能够理解抽象类与接口的标准设计理念,兴许对面向对象分析与设计大有裨益。
restTemplate源码解析(一)构造restTemplate的Bean实例的更多相关文章
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- [Java多线程]-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- restTemplate源码解析(目录)
restTemplate是spring实现的,基于restful风格的http请求模板.使用restTemplate可以简化请求操作的复杂性,同时规范了代码风格.本系列文章,将根据以下目录顺序,从源码 ...
- restTemplate源码解析(五)处理ClientHttpResponse响应对象
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们执行了ClientHttpRequest与服务端进行交互.并返回了一个 ...
- restTemplate源码解析(二)restTemplate的核心逻辑
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们构造了一个RestTemplate的Bean实例对象.本文将主要了解一 ...
- restTemplate源码解析(三)创建ClientHttpRequest请求对象
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们大体看了一下restTemplate的核心逻辑.再回顾一下核心代码 p ...
- restTemplate源码解析(四)执行ClientHttpRequest请求对象
所有文章 https://www.cnblogs.com/lay2017/p/11740855.html 正文 上一篇文章中,我们创建了一个ClientHttpRequest的实例.本文将继续阅读Cl ...
- springcloud源码解析(目录)
springcloud是一个基于springboot的一站式企业级分布式应用开发框架.springboot为其提供了创建单一项目的便利性,springcloud组合了现有的.常用的分布式项目的解决方案 ...
- Spring AOP的实现及源码解析
在介绍AOP之前,想必很多人都听说AOP是基于动态代理和反射来实现的,那么在看AOP之前,你需要弄懂什么是动态代理和反射及它们又是如何实现的. 想了解JDK的动态代理及反射的实现和源码分析,请参见下面 ...
随机推荐
- unless it is in a subquery contained in a HAVING clause or a select list.
sql查询报错: An aggregate may not appear in the WHERE clause unless it is in asubquery contained in a HA ...
- PHP中的符号 ->、=> 和 :: 分别表示什么意思?
php新手经常碰到的问题,->.=> 和 :: 这三个家伙是什么分别都是做什么的啊!看着就很晕. 没关系,下面我们做一下详细的解释,如果你有C++,Perl基础,你会发现这些家伙和他们里面 ...
- 001-java 设计模式概述
一.概述 思维导图 GoF(“四人帮”,又称Gang of Four,即Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides) 1 ...
- 37 Flutter仿京东商城项目 结算页面布局
加群452892873 下载对应34课文件,运行方法,建好项目,直接替换lib目录 CheckOut.dart import 'package:flutter/material.dart'; impo ...
- python之json处理
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standard ECMA-262 3rd Edition - Decembe ...
- python 中 logging 模块的 log 函数以及坑
记录下吧,一个日志的函数,但有个坑是在调用函数时需要先将函数实例化为一个变量,否则进入某个循环时会多次刷新日志: """ 日志模块 """ ...
- html的css背景图的repeat
HTML里background-image中,可以设置background-repeat实现平铺,前面博文中关于css样式换行的(相关博文:超文本css样式换行),其中有个三个div组合的,中间的di ...
- LVS+KeepAlived+Nginx高可用实现方案
文章目录概念LVSKeepAlived为什么要使用准备软件安装KeepAlived 安装源码安装yum安装服务启动.重启.关闭安装ipvsadmnginx安装防火墙(iptables)防火墙配置(方式 ...
- .git泄露及利用php弱类型松散比较构造json的payload
一道ctf题,文章搬运到了自己的网站上: http://101.132.137.140:202/archives/2019-11-16
- leetcode1105 Filling Bookcase Shelves
思路: dp[i]表示摆放好前i本书所需要的最小代价. 实现: class Solution { public: int minHeightShelves(vector<vector<in ...