使用spring-boot-starter-amqp开发生产者应用
近几年来,以信息为中心的表述性状态转移(Representational State Transfer,REST)已经称为替代传统SOAP Web 服务的流行方案。
REST与RPC几乎没有任何关系。RPC是面向服务的,并关注于行为和动作;而REST是面向资源的,强调描述应用程序的事物和名词。
RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。 其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。
delete() 在特定的URL上对资源执行HTTP DELETE操作
exchange() 在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的
execute() 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象
getForEntity() 发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象
getForObject() 发送一个HTTP GET请求,返回的请求体将映射为一个对象
postForEntity() POST 数据到一个URL,返回包含一个对象的ResponseEntity,这个对象是从响应体中映射得 到的
postForObject() POST 数据到一个URL,返回根据响应体匹配形成的对象
headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头
optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息
postForLocation() POST 数据到一个URL,返回新创建资源的URL
put() PUT 资源到特定的URL
RestTemplate的核心之一 Http Client
目前通过RestTemplate 的源码可知,RestTemplate 可支持多种 Http Client的http的访问,如下所示:
- 基于 JDK HttpURLConnection 的 SimpleClientHttpRequestFactory,默认。
- 基于 Apache HttpComponents Client 的 HttpComponentsClientHttpRequestFactory
- 基于 OkHttp3的OkHttpClientHttpRequestFactory。
- 基于 Netty4 的 Netty4ClientHttpRequestFactory。
其中HttpURLConnection 和 HttpClient 为原生的网络访问类,OkHttp3采用了 OkHttp3的框架,Netty4 采用了Netty框架。
RestTemplate类的继承结构
通过IDE的工具可以看到RestTemplate的继承结构很简单:
由图可以看出继承了一个类,实现了一个接口,我们来看看这些接口和类有什么作用。
HttpAccessor:官方文档这样描述:Base class for RestTemplate and other HTTP accessing gateway helpers, defining common properties such as the ClientHttpRequestFactory to operate on.可以看出,这个抽象类不仅可以作为RestTemplate的基类,还可以让其他http访问网关助手去继承,然后就可以获得它的功能了,同时呢,这个抽象类是设置一些共有的属性,其中ClientHttpRequestFactory就是在这里设置的。在我看来,这种抽象类是在避免样板代码,把共有的代码放到上层,但是如果要设置其他共有属性呢,只能一层层继承下去了。比如接下来要看的InterceptingHttpAccessor。
InterceptingHttpAccessor:Base class for RestTemplate and other HTTP accessing gateway helpers, adding interceptor-related properties to HttpAccessor's common properties.就是加了一系列拦截器,这些拦截器会在请求执行之前执行,比如添加一些请求头之类的,http Basic认证就可以通过这种方式来加上去,spring提供这个类BasicAuthorizationInterceptor。至于这个接口为什么给定义的方法ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)三个这样的参数,还得去想想。
RestOperations:Interface specifying a basic set of RESTful operations. Implemented by RestTemplate. Not often used directly, but a useful option to enhance testability, as it can easily be mocked or stubbed.这个接口是和RESTful api配套的,指定RESTful基本操作集。也就是说这个接口说明了一种能力,一种可以发各种rest请求的能力。
从上面的分析来看呢,RestTemplate类继承了可以设置共有属性的类,有了基础的http请求功能,然后实现了RESTful基本操作集的接口,有了发rest请求的能力,当然这个能力得RestTemplate它自己去利用这些共有属性去实现了。这么一组合呢,RestTemplate就可以拿来用了。当然,http协议是比较复杂的,各种请求头啊、不同的数据格式啊等等,这些问题的处理逻辑当然不会放在RestTemplate这个类中,不然会写的很长。所以就有了很多委托类,为了让用户有自己的扩展,这些委托类一般都采用了策略模式来设计,其实就是多态。接下来我们就来看看这些委托类以及它们的设计思想。
先大概看看RestTemplate有什么属性,也就是委托类,它的功能肯定要依靠这些属性来实现的。
1、先来看看messageConverters消息转换器,这是干嘛用的呢?
- 看HttpMessageConverter<T>这个接口的描述Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.可以看到这是一个策略接口,策略模式见《行为类模式--策略模式》然后就是说它可以从request和response转换数据,也就是T类型和request支持的mime(多功能网络邮件扩展协议)类型数据互相转换。比如User这个类转换成json格式,也可以把json格式的User转换成User类,当然还有其他的mime类型。
- 从RestTemplate的构造方法可以看到,你可以使用默认的转换器,如下:
public RestTemplate() {
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());
this.messageConverters.add(new SourceHttpMessageConverter<Source>());
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());
}
}
还可以使用自己准备的消息转换器,有这样的构造方法。可以去查看它的源码。
- 拿其中一个转换器来说明,AllEncompassingFormHttpMessageConverter这个转换器继承了FormHttpMessageConverter,FormHttpMessageConverter的描述太长了,可以去官方文档查看https://docs.spring.io/spring/docs/4.3.17.BUILD-SNAPSHOT/javadoc-api/,它可以读写常规的表单类型,也就是application/x-www-form-urlencoded,但是只能写multipart类型数据,不能读,那如果要读的话是用哪个转换器呢?还得去看看。有意思的是,描述的最后一句话,Some methods in this class were inspired by org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity.说明spring还是参考了apache在这方面的实现,刚好我最近做的一个api测试工具就是用到apache的MultipartEntityBuilder来构建httpEntity。
从它的属性和构造方法可知,每个part可以是不同的数据类型,然后有多个partConverter来解析这些数据。同时呢,它所支持的mime类型也初始化了,然后在实现HttpMessageConverter<T>的canRead、canWrite方法时就能用到了。接下来看看read和write方法,它们是怎么实现的,我们可以从实现的角度来看这两个方法的参数设置有什么学问,如果是自己来设计的话,会是什么样呢?
可以从它的代码看到,首先从HttpInputMessage获得一个流,为什么是这个接口,这个接口有什么用,还有一个HttpOutputMessage,这两个有什么区别,还得思考思考,暂且跳过这个问题,接下来就是得到一个字符串了,然后通过“&”这个符号分割,放到MultiMap里返回出去了。clazz这个参数没有用到,在别的转换器有用的,但是还不知道有什么用。总的看来,这是读常规表单的数据,并没有读multipart类型的,也没有这样类似的read方法了。
write的话从代码可以看出能写两种格式,常规表单和multipart,具体的逻辑可查看它的源码。
我们可以看到FormHttpMessageConverter这个类里还有一个私有的静态类,只能内部使用,是用来写一个mime类型的数据。multipart类型有多个不同类型的part,写每个part到OutputStream时都要用到一个转换器,而这个转换器需要一个HttpOutputMessage实现类,并不是一个OutputStream,所以封装一下,然后通过HttpOutputMessage的方法(也是入口)来改变OutputStream。
这里有个问题,为什么是静态类。私有类还好理解,这个类只在FormHttpMessageConverter里使用,当然弄成私有类是合理的。静态内部类是嵌套类,它不能访问外围类的非静态成员,只能访问静态成员,除此之外,我觉得之所以要弄成静态类,是要说明这个内部类只是一个嵌套类,并不是外围类的一部分,关系不是很亲密。关于具体的区别可以参考这里。
2、接下来看看ResponseErrorHandler这个接口的功能,有两个方法hasError、handleError,入参都是ClientHttpResponse,spring自己定义的一个接口。
入参都是一个接口,这一层层的继承,肯定经过深思熟虑过的设计了,先跳过它。RestTemplate使用的是默认的错误处理器,逻辑很简单,如果hasError为真,就调用handleError,处理的逻辑用户自己实现了,在这个默认的处理器中,就是抛出异常HttpClientErrorException,这个异常又是一系列的接口继承:
要知道,每个接口展现的就是这个层面的功能,这样可以把一个大功能分成一个个独立的小功能,然后在具体的业务逻辑中去配对使用,也就是要什么功能就用哪个接口,同时又对其他的功能不了解,也不关心。这有点像tcp/ip协议的分层。先跳过,有空再来看看。
每次执行请求得到response后,就会使用这个错误处理器,先看看有没有错误,有的话就处理,没有就跳过。
看他怎么获得errorHandler的,是通过一个获取方法,在effective java里有提到过这种方式,叫query method,在RestTemplate里除了set、get外,没有别的地方会直接通过this.errorHandler的方式来引用对象。估计在其他类也是一样。
处理错误后抛出异常就结束了,看来抛出的那个异常很重要啊,spring肯定会捕获到这个异常来展示一些信息。
3、接下来就是看看UriTemplateHandler这个接口,RestTemplate使用的也是默认的uri模板处理器,作用呢就是组装uri,有不同的组装方式,所以也就有不同的实现类。
UriTemplateHandler在execute这个比较底层的方法使用,也就是抽象出的步骤比较靠后。DefaultUriTemplateHandler是使用UriComponentsBuilder来扩展uri的。
3、接下来就是RestTemplate最主要的步骤了:
例如上面是restTemplate源码中的getForObject和getForObject的 调用
RestTemplate的主要逻辑就是这三步了,第一和第三步分别交给了RequestCallback、ResponseExtractor,来看看是怎么实现并使用这两个接口的。
首先是RequestCallback,官方描述Callback interface for code that operates on a ClientHttpRequest. Allows to manipulate the request headers, and write to the request body.
Used internally by the RestTemplate, but also useful for application code.,它是个回调接口,而且是对ClientHttpRequest操作的,方法就一个doWithRequest, ClientHttpRequest作为它的输出参数,很简单。然后它的实现也很简单,而且实现都在RestTemplate里,还是私有类,这个接口看来是个小众接口,使用范围不是很广。具体的实现可以查看源码。
然后瞧瞧ResponseExtractor这个接口,官方描述Generic callback interface used by RestTemplate's retrieval methods Implementations of this interface perform the actual work of extracting data from a ClientHttpResponse, but don't need to worry about exception handling or closing resources.Used internally by the RestTemplate, but also useful for application code.也是一个普通的回调接口,而且不用在实现这个方法的时候担心异常处理和资源关闭的问题,因为这个方法是抛出异常的。
它有三个实现类,一个是从response里抽取headers,一个是抽取httpEntity,另一个就有意思了,
这个实现类封装了HttpMessageConverterExtractor,相当于做了一个代理,目的是获得ResponseEntity<T>这个类型的数据,如下图。
4、到这里呢,RestTemplate的实现介绍完了,接下来会介绍在springboot中它是怎么自动注入的,也好了解下springboot的自动配置。
使用spring-boot-starter-amqp开发生产者应用的更多相关文章
- 从零开始开发一个Spring Boot Starter
一.Spring Boot Starter简介 Starter是Spring Boot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境( 条件 ...
- 最详细的自定义Spring Boot Starter开发教程
1. 前言 随着Spring的日渐臃肿,为了简化配置.开箱即用.快速集成,Spring Boot 横空出世. 目前已经成为 Java 目前最火热的框架了.平常我们用Spring Boot开发web应用 ...
- Spring Boot Starter 开发指南
Spring Boot Starter是什么? 依赖管理是任何复杂项目的关键部分.以手动的方式来实现依赖管理不太现实,你得花更多时间,同时你在项目的其他重要方面能付出的时间就会变得越少. Spring ...
- SpringBoot 之Spring Boot Starter依赖包及作用
Spring Boot 之Spring Boot Starter依赖包及作用 spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. spri ...
- Spring Boot Starter列表
转自:http://blog.sina.com.cn/s/blog_798f713f0102wiy5.html Spring Boot Starter 基本的一共有43种,具体如下: 1)spring ...
- Spring Boot Starter 介绍
http://www.baeldung.com/spring-boot-starters 作者:baeldung 译者:http://oopsguy.com 1.概述 依赖管理是任何复杂项目的关键部分 ...
- spring -boot s-tarter 详解
Starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合.你可以获取所有Spring及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符.例如,如果你想使用Sprin ...
- 手把手教你定制标准Spring Boot starter,真的很清晰
写在前面 我们每次构建一个 Spring 应用程序时,我们都不希望从头开始实现具有「横切关注点」的内容:相反,我们希望一次性实现这些功能,并根据需要将它们包含到任何我们要构建的应用程序中 横切关注点 ...
- 年轻人的第一个自定义 Spring Boot Starter!
陆陆续续,零零散散,栈长已经写了几十篇 Spring Boot 系列文章了,其中有介绍到 Spring Boot Starters 启动器,使用的.介绍的都是第三方的 Starters ,那如何开发一 ...
- 一个简单易上手的短信服务Spring Boot Starter
前言 短信服务在用户注册.登录.找回密码等相关操作中,可以让用户使用更加便捷,越来越多的公司都采用短信验证的方式让用户进行操作,从而提高用户的实用性. Spring Boot Starter 由于 S ...
随机推荐
- vRO Extend VirtualDisk Workflow
https://vbombarded.wordpress.com/2015/02/20/vrealize-orchestrator-extend-virtual-disk-workflow/ var ...
- 实现HTML格式的数据报表邮件
- 使用eclipse搭建第一个python+Django的web开发实例
python+Django的web开发实例 一.创建一个项目如果这是你第一次使用Django,那么你必须进行一些初始设置.也就是通过自动生成代码来建立一个Django项目--一个Django项目的 ...
- springmvc-restful
1.restful概述 REST 仅仅是一种架构的风格,并不是真正的架构,也不是一个软件,而是一种思想. 我们可以基于现有的HTTP.URI.XML.等现有技术来实现REST的风格.而不用去学习任何新 ...
- HMM简单理解(来自quora&其他网上资料)
转载自quora: 连接:https://www.quora.com/What-is-a-simple-explanation-of-the-Hidden-Markov-Model-algorithm ...
- java.sql.SQLException: Incorrect string value: '\xF0\x9F\x91\x88\xE6\x88...' for column 'content' at row 1
往MySQL插入数据时,报错如下 java.sql.SQLException: Incorrect at com.mysql.cj.jdbc.exceptions.SQLError.createSQL ...
- 分开统计的sql写法
DECLARE @StartDate DATETIME= '2017-10-13 00:00:00';DECLARE @EndDate DATETIME= '2017-11-13 23:00:00'; ...
- openstack live migration性能分析
http://blog.zhaw.ch/icclab/an-analysis-of-the-performance-of-live-migration-in-openstack/ http://blo ...
- Linux下DB2的TCP配置
1切换到db2实例用户下(uppdb) su - uppdb 2查看db2是否开启tcp服务 db2set -all 设置tcp服务:db2set DB2COMM=TCPIP 3查看是否配置db2 t ...
- php 策略模式案例
策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境. eg:假如有一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告.在传统的代码中,都是在 ...