专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
Java基基  ·  京东一面:Spring ... ·  昨天  
Java基基  ·  京东一面:Spring ... ·  昨天  
芋道源码  ·  盘点那些令人目瞪口呆的 bug! ·  昨天  
芋道源码  ·  Spring Event + DDD = 王炸!! ·  3 天前  
Java编程精选  ·  Springboot代码混淆,别再让代码在线 ... ·  3 天前  
芋道源码  ·  魔改xxl-job,彻底告别手动配置任务! ·  4 天前  
51好读  ›  专栏  ›  ImportNew

REST 架构风格的由来 & 元素

ImportNew  · 公众号  · Java  · 2016-12-14 20:59

正文

(点击上方蓝字,快速关注我们)


来源:伯乐在线专栏作者 - 求知者

点击 → 了解如何加入专栏作者

如需转载,发送「转载」二字查看说明


一 REST架构风格的由来


笔者听到REST也有快两个年头了,但是就笔者而言,身边的同事,朋友谈论它的很多,但总感觉说的有些欠缺,听的人也感觉迷迷糊糊的。包括笔者的资深架构师同事也对REST的理解感觉不是那么的地道,都停留在一个模棱两可的程度。如果要细究REST,谁也说不出个一二,这让笔者感觉很揪心。


本文只是笔者研究REST的一个总结,部分内容来源于由李锟、廖志刚、刘丹、杨光等对Feilding的论文的译文,如果能对看到的朋友理解REST是什么有点帮助,那笔者也就甚是欣慰了。在笔者的心目中,对于一个技术点的掌握要达到炉火纯青的地步方可才能传道授业解惑。笔者也在朝着这个方向砥砺前行,希望有朝一日,但凡由笔者分享出去的技术能给在这条技术的路上前行的大伙一些真正的干货。闲谈的有点多,如上内容姑且就当是笔者为什么要写这篇博客的缘由吧。


1.创建REST的动机


作者开发 REST 的动机是为 Web 应该如何运转创建一种架构模型,使之成为 Web 协议标准的指导框架。REST 被用来描述想要得到的 Web 架构,帮助识别出现有的问题,对各种替代方案进行比较,并且保证协议的扩展不会违反使 Web 成功的那些核心约束。


REST 的第一版开发于 1994 年 10 月和 1995 年 8 月之间,起初是作为作者编写 HTTP/1.0规范和最初的HTTP/1.1 建议时,用来沟通各种 Web 概念的一种方法。它在随后的 5 年中以迭代的方式不断改进,并且被应用于各种 Web 协议标准的修订版和扩展之中。


2.明确定义


REST是一种架构风格,Roy Thomas Fielding 2000年在加州大学欧文分校的博士论文 《Architectural Styles and the Design of Network-based Software Architectures》中文译为《架构风格与基于网络的软件架构设计》中对REST(Representational State Transfer,表述性状态转移)进行了详细的描述。这篇论文定义了一个框架,致力于通过架构风格来理解软件架构,并且展示如何使用风格来指导基于网络的应用的架构设计。


Fielding:Adobe首席科学家,Apache HTTP Server Project的联合创始人,当过ASF的理事,HTTP规范的重要作者之一。


3.架构风格


它是一组协作的架构约束。这些约束限制了架构元素的角色和功能,以及在任何一个遵循该风格的架构中允许存在的元素之间的关系。约束往往是由在架构元素的某个方面使用软件工程原则来驱动的。


4.软件架构


何为软件架构,该领域的研究者们从未达成过统一的定义,由于现代软件系统的复杂性,系统实现被划分为独立的组件,这些组件通过相互通信来执行想要完成的任务。软件架构研究如何以最佳方式划分一个系统、如何标识组件、组件之间如何通信、信息如何沟通、组成系统的元素如何能够独立地进化,以及上述的所有东西如何能够使用形式化的和非形式化的符号加以描述。


Fielding对软件架构的定义为:一个软件架构是一个软件系统在其操作的某个阶段的运行时元素的抽象。一个系统可能由很多层抽象和很多个操作阶段组成,每个抽象和操作阶段都有自己的软件架构。


软件架构由一些架构元素(组件、连接器和数据)的配置来定义,这些元素之间的关系受到约束,以获得想要得到的一组架构属性。


组件是软件指令和内部状态的一个抽象单元,通过其接口提供对于数据的转换。


连接器是对于组件之间的通讯、协调或者合作进行仲裁的一种抽象机制(连接器的例子包括共享的表述、远程过程调用、消息传递协议和数据流)。数据是组件通过一个连接器接收或发送的信息元素。配置是在系统的运行期间组件、连接器和数据之间的架构关系的结构。


 5.架构属性


它包括了对组件、连接器和数据的选择和排列所导致的所有的属性(包括了可以由系统获得的功能属性和非功能属性,例如:进化的相对容易程度、组件的可重用性、效率、动态扩展能力,这些常常被称作品质属性)。


关键关注点架构属性:性能(网络性能、延迟、完成时间、网络效率),可伸缩性,简单性,可修改性(可进化性、可扩展性、可定制性、可配置性、可重用性),可见性, 可移植性, 可靠性。


REST强调组件交互的可伸缩性、接口的通用性、组件的独立部署、以及用来减少交互延迟、增强安全性、封装遗留系统的中间组件。


6.作者列出的架构风格


6.1.数据流风格(Data-flow Styles)


6.1.1 管道和过滤器(Pipe and Filter,PF)


每个组件(过滤器)从其输入端读取数据流并在其输出端产生数据流,通常对输入流应用一种转换并增量地处理它们,以使输出在输入被完全处理完之前就能够开始。这种风格也被称作单路数据流网络(one-way data flow network)。


6.1.2 统一管道和过滤器(Uniform Pipe and Filter,UPF)


该风格在 PF 风格的基础上,添加了一个约束,即所有过滤器必须具有相同的接口。


6.2.复制风格(Replication Styles)


6.2.1 复制仓库(Replicated Repository,RR)


基于复制仓库风格的系统通过利用多个进程提供相同的服务,来改善数据的可访问性和服务的可伸缩性。这些分散的服务器交互为客户端制造出只有一个集中的服务的“幻觉”。主要的例子包括诸如 XMS 这样的分布式文件系统和 CVS这样的远程版本控制系统。


6.2.2 缓存(Cache,$)


复制仓库风格的一种变体是缓存风格,复制个别请求的结果,以便可以被后面的请求重用。


6.3.分层风格(Hierarchical Styles)


6.3.1 客户-服务器(Client-Server,CS)


该风格在基于网络的应用的架构风格中最为常见。服务器组件提供了一组服务,并监听对这些服务的请求。客户端组件通过一个连接器将请求发送到服务器,希望执行一个服务。服务器可以拒绝这个请求,也可以执行这个请求并将响应发送回客户端。


6.3.2 分层系统(Layered System,LS)


一个分层系统是按照层次来组织的,每一层为在其之上的层提供服务,并且使用在其之下的层所提供的服务。尽管分层系统被看作一种“单纯”的风格,但是它在基于网络的


系统中的使用仅限于与客户-服务器风格相结合,形成分层-客户-服务器风格。分层系统的例子包括分层通信协议的处理,例如 TCP/IP 和OSI 协议栈。


6.3.3 分层-客户-服务器(LayeredClient-Server,LCS)


该风格在客户-服务器风格的基础上添加了代理(proxy)组件和网关(gateway)组件。一个代理组件作为一个或多个客户端组件的共享服务器,它接收请求并进行可能的转换后将其转发给服务器。一个网关组件在客户端或代理看起来像是一个正常的服务器,但是事实上它将请求进行可能的转换后转发给了它的“内部层”(inner- layer)服务器。这些额外的中间组件添加了很多个层,用来为系统添加诸如负载均衡和安全性检查这样的功能。


6.3.4 客户-无状态-服务器(Client-Stateless-Server,CSS)


该风格源自客户-服务器风格,并且添加了额外的约束:在服务器组件之上不允许有会话状态(session state)。从客户端发到服务器的每个请求必须包含理解请求所必需的全部信息,不能利用任何保存在服务器上的上下文(context),会话状态全部保存在客户端。


6.3.5 客户-缓存-无状态-服务器(Client-Cache-Stateless-Server,C$SS)


该风格来源于客户-无状态-服务器风格和缓存风格(通过添加缓存组件)。


6.3.6 分层-客户-缓存-无状态-服务器(Layered-Client-Cache-StatelessServer,LC$SS)


该风格通过添加代理或网关组件,继承了分层-客户-服务器风格和客户-缓存-无状态-服务器风格。使用此风格的范例系统是 Internet 域名系统(DNS)。


6.3.7 远程会话(Remote Session,RS)


该风格是客户-服务器风格的一种变体,它试图使客户端组件(而非服务器组件)的复杂性最小化或者使得它们的可重用性最大化。每个客户端在服务器上启动一个会话,然后调用服务器的一系列服务,最后退出会话。应用状态被完全保存在服务器上。这种风格通常在以下场合中使用:想要使用一个通用的客户端(例如 TELNET)或者通过一个模仿通用客户端的接口(例如 FTP )来访问远程服务。


6.3.8 远程数据访问(Remote Data Access,RDA)


该风格是客户-服务器风格的一种变体,它将应用状态分布在客户端和服务器上。客户端以一种标准的格式发送一个数据库查询(例如 SQL)请求到服务器,服务器分配一个工作空间并执行这个查询,这可能会导致一个巨大的结果集。客户端能够在结果集上进行进一步操作(例如表连接)或者每次获取结果的一部分。客户端必须了解服务的数据结构,以便建造依赖于该结构的查询。


6.4.移动代码风格(Mobile Code Styles)


6.4.1 虚拟机(Virtual Machine,VM)


所有移动代码风格的基础是虚拟机(或解释器)风格。代码必须以某种方式来执行,首选的方式是在一个满足了安全性和可靠性关注点的受控环境中执行,而这正是虚拟机风格所提供的。


6.4.2 远程求值(Remote Evaluation,REV)


该风格来源于客户-服务器风格和虚拟机风格,一个客户端组件必须要知道如何来执行一个服务,但缺少执行此服务所必需的资源(CPU 周期、数据源等等),这些资源恰好位于一个远程站点上。因此,客户端将如何执行服务的代码发送给远程站点上的一个服务器组件,服务器组件使用可用的资源来执行代码,然后将执行结果发送回客户端。


6.4.3 按需代码(Code on Demand,COD)


在该风格中,一个客户端组件知道如何访问一组资源,但不知道如何处理它们。它向一个远程服务器发送对于如何处理资源的代码的请求,接收这些代码,然后在本地执行这些代码。


6.4.4 分层-按需代码-客户-缓存-无状态-服务器(Layered-Code-on-DemandClient-Cache-Stateless-Server,LCODC$SS)


将按需代码风格添加到上面讨论过的分层-客户-缓存-无状态-服务器风格上。因为代码被看作不过是另一种数据元素,因此这并不会妨碍LC$SS 风格的优点。


6.4.5 移动代理(Mobile Agent,MA)


在该风格中,一个完整的计算组件,与它的状态、必需的代码、执行任务所需的数据一起被移动到远程站点。该风格可以看作来源于远程求值风格和按需代码风格,因为移动性是同时以这两种方式工作的。


6.5.点对点风格(Peer-to-Peer Styles)


6.5.1 基于事件的集成(Event-based Integration,EBI)


该风格不是直接调用另一个组件,而是一个组件能够发布(或广播)一个或者多个事件。在事件发布后,系统中的其他组件能够注册对于某些事件类型的兴趣,由系统本身来调用所有已注册的组件。


6.5.2 C2


C2 架构风格直接支持大粒度的重用,并且通过加强底层独立性,支持系统组件的灵活组合。它通过将基于事件的集成风格和分层-客户-服务器风格相结合来达到这些目标。


6.5.3 分布式对象(Distributed Objects,DO)


该风格将系统组织为结对进行交互的组件的集合。一个对象是一个实体,这个实体封装了一些私有的状态信息或数据、操作数据的一组相关的操作或过程、以及一个可能存在的控制线程,这种封装使得它们能够被整体地看作单个的单元。


6.5.4 被代理的分布式对象(Brokered Distributed Objects,BDO)


该风格引入了名称解析组件——其目的是将该组件接收到的客户端请求中一个通用的服务名称解析为一个能够满足该请求的对象的特定名称,并使用这个特定名称来答复客户端。


7.REST所继承的风格约束



每种风格的详细解释见第六小节。



二 REST架构风格的架构元素


表述性状态转移(REST)风格是对分布式超媒体系统中的架构元素的一种抽象。REST忽略了组件实现和协议语法的细节,以便聚焦于以下几个方面:组件的角色、组件之间的交互之上的约束、组件对重要数据元素的解释。REST包括了一组对于定义 Web 架构基础的组 件、连接器和数据的基本约束,因此它代表了基于网络的应用的行为的本质。


REST提供了一组架构约束,当作为一个整体来应用时,强调组件交互的可伸缩性、接口的通用性、 组件的独立部署、以及用来减少交互延迟、增强安全性、封装遗留系统的中间组件。


如下为REST的架构元素。


1.数据元素(Data Elements)




1.1资源和资源标识符(Resources and Resource Identifiers)


REST对于信息的核心抽象是资源。任何能够被命名的信息都能够作为一个资源:一份文档或一张图片、一个与时间相关的服务(例如,“北京今日的天气”)、一个其他资源的集合、一个非虚拟的对象(例如,人)等等。REST使用一个资源标识符来标识组件之间交互所涉及到的特定资源。


1.2表述(Representations)


REST组件通过以下方式在一个资源上执行动作:使用一个表述来捕获资源的当前的或预期的状态、在组件之间传递该表述。一个表述是一个字节序列,以及描述这些字节的表述元数据。表述的其他常用但不够精确的名称包括:文档、文件、HTTP 消息实体、实例或变量。表述的数据格式被称为一种媒体类型。


2.连接器(Connectors)




REST使用多种不同的连接器类型来对访问资源和转移资源表述的活动进行封装。连接器代表了一个组件通信的抽象接口,通过提供清晰的关注点分离、 并且隐藏资源的底层实现和通信机制,从而改善了架构的简单性。接口的通用性也使得组件 的可替换性成为了可能:如果用户对系统的访问仅仅是通过一个抽象的接口,那么接口的实现就能够被替换,而不会对用户产生影响。由于组件的网络通信是由一个连接器来管理的,所以在多个交互之间能够共享信息,以便提高效率和响应能力。


3.组件(Components)




REST 组件根据它们在整个的应用动作中的角色来进行分类。


说明:本文参考了由李锟、廖志刚、刘丹、杨光等翻译的>的部分内容。笔者很是佩服他们强烈的社会责任感,他们无私的翻译了Feilding的博士论文给国人,再次向他们拜谢。


觉得本文对你有帮助?请分享给更多人

关注「ImportNew」,提升Java技能


专栏作者简介 ( 点击 → 加入专栏作者 )


求知者:一个前行中的程序员。

打赏支持作者写出更多好文章,谢谢!