2016-12-28 by 安静的下雪天  http://www.cnblogs.com/quiet-snowy-day/p/6228198.html 

提示:使用手机浏览时请注意,图多费流量。

本篇概要

RestTemplate类图

RestTemplate 类中省略了静态成员变量、变量的set/get方法以及实现的接口方法,

RestOperations 接口中省略了参数类型及重载的方法。这样既可以保证各个要素尽量在一幅图中展现,又不会影响理解。

返回顶部

postForEntity 处理过程

以postForEntity方法作为切入点,来梳理一下请求是如何执行的,以下概要流程图。(灰色方框内为doExcute方法的内部处理。)

postForEntity方法中,创建了两个内部类对象requestCallback和responseExtractor并传递给execute方法,分别用于请求和响应的关键处理。
总结了一下,不管是请求还是响应,这里的关键处理就是明确资源的媒体类型(也就是要明确请求端和响应端交换的信息的格式),
根据媒体类型选择适合的解析器,将消息写入输出流或者从输入流读入。

返回顶部

requestCallback.doWithRequest 处理过程

——内部类AcceptHeaderRequestCallback.doWithRequest的处理。
发送请求时,Http头部需要设置Accept字段,该字段表明了发送请求的这方接受的媒体类型(消息格式),也是响应端要返回的信息的媒体类型(消息格式)。
根据postForEntity方法的第三个参数responseType,程序将选择适合的解析器XXXConverter,并依据该解析器找出所有支持的媒体类型。
 
 ——内部类HttpEntityRequestCallback.doWithRequest的处理。
如果是POST请求并且消息体存在时,除了设置Accept字段,还可能需要设置Content-Type字段,该字段表明了所发送请求的媒体类型(消息格式),也是响应端接受的媒体类型(消息格式)。
根据postForEntity方法的第二个参数request,程序将选择适合的解析器XXXConverter,将请求消息写入输出流。
返回顶部

responseExtractor.extractData 处理过程

与请求消息体的处理过程相似。

虽然,postForEntity方法中responseExtractor对象的类型为ResponseEntityResponseExtractor,但是实际执行处理过程是HttpMessageConverterExtractor的对象实例。
在postForObject方法中,则是直接使用了HttpMessageConverterExtractor创建对象。

下图画出的也是HttpMessageConverterExtractor类中的extractData方法的处理过程。

返回顶部

关于GenericHttpMessageConverter

在以上几个方法的梳理过程中,我注意到每次消息解析转换都要作GenericHttpMessageConverter分支判断,为什么呢?

GenericHttpMessageConverter接口继承自HttpMessageConverter接口,二者都是在org.springframework.http.converter路径下。
此包中还有其他几种Converter实现类,看名字就可以猜到主要功能。唯独GenericHttpMessageConverter没猜出来。
于是,我在eclipse中使用Ctrl+Shift+G快捷键搜索了一下它的实现类AbstractGenericHttpMessageConverter。
看到AbstractJackson2HttpMessageConverter类的时候,我好像明白了。
GenericHttpMessageConverter是其他转换器派生类的接口,用于解析特殊格式的资源,比如json,xml等。
返回顶部

关于RestTemplate 中的转换器列表

转换器列表messageConverters是final类型的,由RestTemplate的构造函数赋值。一旦创建了RestTemplate对象,该对象也就同时拥有了一个当前系统支持的转换器列表。
 
那么,对于需要引用jar包的转换器,RestTemplate是怎么添加转换器实例的呢?
在声明messageConverters列表之前,定义了几个布尔型静态常量,该常量是对某一个特殊类是否可以被加载的判断结果。
在RestTemplate的构造函数中,根据该常量值来判断是否将某个转换器的实例加入到列表中。
    private static boolean romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", RestTemplate.class.getClassLoader());

    private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", RestTemplate.class.getClassLoader()); private static final boolean jackson2Present =
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", RestTemplate.class.getClassLoader()) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", RestTemplate.class.getClassLoader()); private static final boolean jackson2XmlPresent =
ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", RestTemplate.class.getClassLoader()); private static final boolean gsonPresent =
ClassUtils.isPresent("com.google.gson.Gson", RestTemplate.class.getClassLoader()); private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
由此可知,RestTemplate的初始化顺序:
创建(new)一个RestTemplate实例时,首先装载RestTemplate类,然后按照出现的顺序转载静态变量或代码。
装载完成之后,进行实例化。首先实例化成员变量,然后执行构造函数。
 
那么,外部引用的类是否可以被加载具体是怎么判断的?
通过ClassUtils.isPresent(String className, ClassLoader classLoader)方法。——感觉ClassUtils可以单独写一篇orz
ClassUtils 类在 spring-core 工程的 org.springframework.util 路径下。
简单来说,isPresent实际上是返回了ClassUtils.forName方法的处理结果,当forName方法正常执行,则鉴定的类被加载,返回true;若抛出异常(注意,此处异常是Throwable)则返回false。
forName方法的处理是:
首先,根据类名的长度(<=8)来确定是否是原始类型,若是原始类型则返回类对象Class<?>。
其次,判断是否是普通类型,若是原始类型则返回类对象Class<?>。
第三,判断是否数组类型,通过过滤"["字符截取类名,递归调用forName方法获取类对象,然后利用反射Array.newInstance创建对象并返回。
最后,排除以上情况后,使用classLoader来加载className指定的类。
 

补充

原始类型:Java的基本类型及其包装类,基本类型的数组类对象,以及空类型void.class。

 
普通类型:
 

返回顶部

【Spring-web】RestTemplate源码学习——梳理内部实现过程的更多相关文章

  1. 【Spring-web】RestTemplate源码学习

     2016-12-22   by 安静的下雪天  http://www.cnblogs.com/quiet-snowy-day/p/6210288.html 前言 在Web开发工作中,有一部分开发任务 ...

  2. spring源码学习(三)--spring循环引用源码学习

    在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...

  3. 捋一捋Spring Web的源码思路

    Servlet前提 Java规定了Servlet Container为每一个web app创建一个Servlet Context:而Servlet Context中又包含了诸多Servlet -- 其 ...

  4. Python Web Flask源码解读(三)——模板渲染过程

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  5. 【目录】Spring 源码学习

    [目录]Spring 源码学习 jwfy 关注 2018.01.31 19:57* 字数 896 阅读 152评论 0喜欢 9 用来记录自己学习spring源码的一些心得和体会以及相关功能的实现原理, ...

  6. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  7. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

  8. Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

    写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...

  9. Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件

    写在前面 从大四实习至今已一年有余,作为一个程序员,一直没有用心去记录自己工作中遇到的问题,甚是惭愧,打算从今日起开始养成写博客的习惯.作为一名java开发人员,Spring是永远绕不过的话题,它的设 ...

随机推荐

  1. 从I/O复用谈epoll为什么高效

    上一篇文章中,谈了一些网络编程的基本概念.在现实使用中,用的最多的就是I/O复用了,无非就是select,poll,epoll 很多人提到网络就说epoll,认为epoll效率是最高的.单纯的这么认为 ...

  2. JavaScript 开发规范

    本篇主要介绍JS的命名规范.注释规范以及框架开发的一些问题. 目录 1. 命名规范:介绍变量.函数.常量.构造函数.类的成员等等的命名规范 2. 注释规范:介绍单行注释.多行注释以及函数注释 3. 框 ...

  3. CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]

    上一篇文章我提到:为了使用"国货",我把 Linux 上的构建和测试委托给了 DaoCloud,而 Travis-CI 不能放着不用啊.还好,这货支持 macOS 系统.所以就把 ...

  4. 【原创】免费申请SSL证书【用于HTTPS,即是把网站从HTTP改为HTTPS,加密传输数据,保护敏感数据】

    今天公司有个网站需要改用https访问,所以就用到SSL证书.由于沃通(以前我是在这里申请的)暂停了免费的SSL证书之后,其网站推荐了新的一个网站来申请证书,所以,今天因为刚好又要申请一个证书,所以, ...

  5. 个人网站对xss跨站脚本攻击(重点是富文本编辑器情况)和sql注入攻击的防范

    昨天本博客受到了xss跨站脚本注入攻击,3分钟攻陷--其实攻击者进攻的手法很简单,没啥技术含量.只能感叹自己之前竟然完全没防范. 这是数据库里留下的一些记录.最后那人弄了一个无限循环弹出框的脚本,估计 ...

  6. [原] KVM 虚拟化原理探究(4)— 内存虚拟化

    KVM 虚拟化原理探究(4)- 内存虚拟化 标签(空格分隔): KVM 内存虚拟化简介 前一章介绍了CPU虚拟化的内容,这一章介绍一下KVM的内存虚拟化原理.可以说内存是除了CPU外最重要的组件,Gu ...

  7. ASP.NET Core 中文文档 第四章 MVC(3.9)视图组件

    作者: Rick Anderson 翻译: 娄宇(Lyrics) 校对: 高嵩 章节: 介绍视图组件 创建视图组件 调用视图组件 演练:创建一个简单的视图组件 附加的资源 查看或下载示例代码 介绍视图 ...

  8. Node.js npm 详解

    一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...

  9. iosselect:一个js picker项目,在H5中实现IOS的select下拉框效果

    具体文档和demo可以访问github:https://github.com/zhoushengmufc/iosselect 移动端浏览器对于select的展示样式是不一致的,ios下是类似原生的pi ...

  10. Android之Pull解析XML

    一.Pull解析方法介绍 除了可以使用SAX和DOM解析XML文件,也可以使用Android内置的Pull解析器解析XML文件.Pull解析器的运行方式与SAX解析器相似.它也是事件触发的.Pull解 ...