Rpc远程调用框架的设计与实现(2)
接上:
3 基于Json的前后端数据交互
3.1 轻量级的数据交换形式
3.1.1 什么是Json
Json(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
Json的构建结构大致有两类:
1.“名称/值”对的集合(A collection of name/value pairs)。不同的语言中,它被理解为对象(object),纪录(record),结构(struct),字典(dictionary),哈希表(hash table),有键列表(keyed list),或者关联数组 (associative array)。
2. 值的有序列表(An ordered list of values)。在大部分语言中,它被理解为数组(array)。
这些都是常见的数据结构。事实上大部分现代计算机语言都以某种形式支持它们。这使得一种数据格式在同样基于这些结构的编程语言之间交换成为可能。
Json共有四种表现形式:
1.对象是一个无序的“‘名称/值’对”集合。一个对象以“{”开始,以“}”结束。每个“名称”后跟一个“:”,“‘名称/值’对”之间使用“,”分隔。
2.数组是值(value)的有序集合。一个数组以“[”开始,“]”结束。值之间使用“,”分隔。
3.值(value)可以是双引号括起来的字符串(String)、数值(number)、true、false、null、对象(object)或者数组(array)。这些结构可以嵌套。
4.字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜体转义。一个字符(character)即一个单独的字符串(characeter string)。
3.1.2 Json的优势
上文提到了Json的一些特性,可以看出,Json可以描述大部分的数据结构。所以Json是适用于Ajax程序的一种很好的格式,原因是它使 JavaScript对象和字符串值之间能够快速的转换。由于Ajax应用程序非常适合将纯文本(字符串)发送给服务器端程序并对应地接收纯文本,相比不能生成文本的API,能生成文本的API自然更可取;而且,Json允许我们方便的处理本地JavaScript对象,而无需为如何表示这些对象多费心思。 虽然XML也可以提供文本方面的类似益处,但用于将 JavaScript对象转换成XML 的几个现有API没有JSON API成熟;有时,在创建和处理 JavaScript 对象时必须格外谨慎以确保所进行的处理能与所选用的XML会话API协作。但对于Json,情况就大不相同:它能处理几乎所有可能的对象类型,并会返回一个非常好的数据表示。因此,Json 的最大价值在于可以将JavaScript真的作为JavaScript而非数据格式语言进行处理。所有有关使用JavaScript对象的技巧都可以应用到代码中,而无需为如何将这些对象转变成文本而多费心思。
3.2 JavaScript与Java间的数据类型
3.2.1 JavaScript与Java常用的数据类型
JavaScript常用的数据类型有以下几种:
主要(基本)数据数据类型:字符串,数值,布尔;
复合(引用)数据类型:对象,数组;
对象中最常用的Date对象,常用于时间的计算。
Java中常用的数据对象有Integer,Double,Float,Boolean,Date,String,Char(这些类都是简单数据类型的封装)等等,集合最常见的有List,Map,Set,Array。
不同的语言对数据有着不同的描述与结构,如何在它们之间建立联系是实现Rpc的关键步骤之一。
3.2.2 利用Json建立JavaScript与Java数据类型的映射关系
在3.1里提到的Json的诸多优势和特性,使其非常适合作为两种编程语言的桥梁。下面是Java与JavaScript之间的数据类型映射表:
序号 |
Java |
JavaScript |
1 |
Integer |
数值,字符串,布尔 |
2 |
Double |
数值,字符串,布尔 |
3 |
Float |
数值,字符串,布尔 |
4 |
Boolean |
字符串,布尔 |
5 |
Date |
字符串 |
6 |
String |
字符串,Date |
7 |
Array, List,Set |
数组 |
8 |
JavaBean Obj,Map |
对象 |
表3-1 Java/JavaScript数据类型映射表
3.3 数据类型转换器
3.3.1 前后端交换数据转化流程
Rpc请求需要客户端->服务端->客户端的数据传递流程,数据转换大致需要进行以下几个步骤:
(1) 将JavaScript方法参数转化为Json字符串传递到服务端(客户端转化)
(2) 服务端解析Json串,并根据服务端方法参数类型将Json串所包含的数据转化为相应的类型(服务端转化)
(3) 执行方法,获取返回值,将返回值转化为Json串(服务端转化)
(4) 客户端接收Json串,并将其转化为Json格式的数据,供客户端访问。(客户端转化)
具体流程图见3-1。
图3-1 前后端数据流图
3.3.2 客户端数据类型转换器的实现
客户端转换器主要有两个转换过程,一种将客户端提交的数据转化为Json串,另外一种是将Json串转化为Js数据类型。因为Json是JavaScript的原生数据类型,故不需要额外的第三方库就能对其进行操作。使用JavaScript内置方法eval就能将Json串转化为Json,这样JavaScript就能对其进行识别了。相对比较麻烦是将各种数据类型转化为Json串的过程,下面就各类型数据一一举例说明转化算法。
简单类型数据统一转化为字符串,比如数值,布尔转化为字符串都是非常容易的。
对象的转化与数组类似,首先获得一个对象中的所有属性,根据属性获取其对应的值,并将这些数据拼接成类似{“a”:”1”,”b”:”2”,”c”:”3”}这样的结构。比如一个对象内有三个属性atr1,atr2,atr3,每个属性的值分别为val1,val2,val3,那么对应的Json串就是{atr1:val1,atr2:val2,atr3:val3}。
数组转化为Json串需要对其进行遍历,先获取数组长度,接着对数组进行循环遍历并拼成类似[a,b,c]这样的数据结构。比如数组内有三个字符串”str1”,”str2”,”str3”,那么对应的Json串则是[“str1”,”str2”,”str3”]。如果数组内的数据是数组类型那么就继续调用转化器将某一结点的值继续转化为Json格式,递归调用转化器直到转化为字符串或对象Json串为止。
上述转化流程图参见图3-2。
图3-3 服务端数据类型转化器算法
4 框架的其他设计
4.1 性能方面的设计
一个可用性高的框架在性能方面一定要有所考虑。要找出整个使用流程中的性能瓶颈,并有针对性的进行优化。
在Rpc远程请求过程中,有以下几个性能关注点:
(1) 客户端,服务端数据格式转化
(2) 动态脚本生成效率
(3) Ajax性能
针对以上几个点,在Rpc远程调用框架内做了一些性能调优:
(1)优化数据转换算法,比如尽量在一次遍历中将所有事情做完,减少循环次数。循环长度一次性获取,不要每次都计算。尽量使用Api中的方法,很多Api是针对Jvm调优过的,性能比自己实现要好。
(2)对动态生成的脚本做缓存,这样可以避免每一次访问都重新生成脚本。
(3)Ajax同步时如遇网络阻塞可能会导致调用无法响应,提供设置异步回调方法的接口,在很多时候可以使用异步Ajax,避免了界面无响应。
4.2 扩展性设计
初期Rpc框架基本是完整实现了所有的流程,随着技术的发展,在某些方面会有一些很好的开源解决方案,为了适应这些发展,需要提供一些可扩展的设计。比如在数据转换这一块,所有的转换器都实现了一个Convertor接口,这样做的好处是可以扩展使用性能更好第三方的转换工具来替代框架的转换方式。只要实现相应的接口即可。对于Cache,框架提供了Cache接口,目前的实现是简单的Map,开源缓存框架也有很多优秀的实现,比如OsCache,MemCache,这些缓存框架上在算法相对比较复杂,同时也能提供更好的性能,集成这些好的组件都是提高Rpc框架性能的很好的手段。
5 结束语
在Web2.0如火如荼的今天,相信Rpc远程调用框架的能够让Ajax开发变的更加简单,方便,目前框架实现了基本的Rpc请求功能,与Spring紧密集成。框架下一步的发展思路是更加简化的配置方式,更加快速的远程调用和以及更加安全的框架,并根据开发需要提供更多的框架集成。