如何实现应用内外交互,是Quick-Fix框架的核心之一,我们常见的应用有提供web服务的(如Spring应用),有进行大数据计算的(如Storm应用),有提供rpc的后台服务(如通过dubbo提供rpc的数据服务),有纯jar服务等;基本上我们可以划分为两类
- 应用本身,有一套健全的与外界交互的机制(这里不包括db/redis等数据的读写)
- 应用只关注自己的服务功能(接收数据,产生数据,保存数据),本身不与第三方的应用进行交互
针对上面这两种case,我们应该怎么来设计一套应用内外交互的方案,来实现接收外部请求,执行应用内部方法或访问应用内部数据,并返回结果的目的?
I. 交互规范设计
因为不同的应用,与外部交互的方式不一样,我们希望最好能直接复用已有的通信机制来实现我们的需求;比如原来就提供了web服务,我们可以在原有的web服务的基础上,新增一个Controller来实现需求;如果应用本身是通过rpc进行通行的,且已经有了非常完善的rpc测试辅助工具,然后就希望可以直接在现在已有的rpc基础上,新增一个服务来实现应用内外交互;再如果我就是一个独立jar应用,我希望通过http方式与外界交互,所以最好框架本身就提供一种默认的交互方案
简单来讲,交互,不能写死,最好是有一个规范,具体想用哪个实现,可以交给实际使用方来选择和扩展
1. 请求参数确认
内外交互,首要的就是确认交互的参数,确定需要哪些基本信息,可以达到我们的目的;以及结果怎么返回
在设计参数之前,再次明确一下我们的目的:
- 执行应用内某个方法
- 访问应用中数据
要实现上面的目的,我们需要些什么?
- service: 用于定位访问的具体类
- field: 用来定位应用中的数据
- method: 需要执行的方法
- params: 方法执行需要传入参数
所以我们的req接口如下
1 | @Data |
2. 请求参数说明
针对请求参数,进行解释
key | 类型 | 解释 |
---|---|---|
service | String | 需要执行的服务,可以是完成路径,可以是beanName |
field | String | 需要访问的服务内部成员属性,值为属性名;为空时,表示执行的服务的某个方法 |
method | String | 方法名,需要执行的方法;为空时,表示访问某个服务的成员属性值 |
type | String | 用来辅助service来定位具体执行的类,如static表示访问的是一个静态类;single表示访问的是单例 |
params | 数组 | 请求参数,数组,可以不存在,格式为 类型#值 ,对于基本类型,可以省略类型的前缀包 |
单独看表,可能不太好理解,下面结合实例进行说明,为什么要这么设计
a. 静态类和实例的访问
在第一篇的整体设计中,就提及到我们采用反射的方式来执行目标方法,因此拿到请求参数后,第一步就是获取执行的类,我们需要执行的是静态类还是实例,对于反射而言,这个差别可不小;因此我们就有了type字段,用来区分service的类型
type可以决定用哪个ServerLoader
来加载传入的Service
比如在框架提供的两种service加载中,对type支持如下
value | 说明 | service取值 |
---|---|---|
static | 表示service传入的是一个静态类的包路径,我们需要访问的是静态类的成员或方法 | service必须是类全路径 |
bean 或不传 或空字符串 | 表示service传入的是Spring的Bean(可以是beanName, 也可以是全路径),我们需要访问的是Spring中某个Bean的成员或方法 | service可以穿beanName or 全路径 |
b. 方法执行
目标方法的执行,可以分为两种,一个是直接访问某个服务or静态类的方法;另外一个是访问某个服务or静态类的成员属性的方法
上面两种有什么区别呢?
- 第一种,通过传入参数,看返回结果,更常见的是为了确认方法的执行逻辑是否有问题
- 第二种,更多是查询或订正内存数据(应用内存数据,往往是以成员属性的方式存在)
所以field,method 这两个参数的组合,就是用来确认上面的两种场景的
case | 组合方式 | 效果 |
---|---|---|
case1 | field 不传,或者field为空,method存在 | 相等于执行service的method方法 |
case2 | field method都存在,且method为field对象可执行的方法 | 分步骤为先获取service中的field属性,然后执行field的method方法 |
c. 传参说明
方法执行,不可避免的就是传参了,参数我们将分为三类
- 基本类型:
int/long/char/boolean/float/double/byte
- 特殊类型:
String/Class/BigDecimal/BigInteger
- 对象
接下来,我们约定下传参的规范
- params 为数组
- 基本类型,传参格式如
int#value
要求 | 格式 | 示例 |
---|---|---|
params | 数组 | [“asd”, “123”] |
基本类型 | 类型#value | ”int#123" , "long@12039123123" , "boolean#true" , "float#123.321" |
BigDecimal | BigDecimal#value | BigDecimal#12.2 |
BigInteger | BigInteger#value | BigInteger#12 |
Class | Class#类全路径 | Class#com.git.hui.fix.example.jar.server.CalculateServer |
String | String#Value 或 Value | "String#Hello" , HelloWorld |
对象 | 全路径#Json序列化对象 | "com.git.hui.fix.example.jar.server.DemoDO#{\"key\":\"kkk\", \"value\":\"aaa11\"}" |
接下来给出以下具体的参数解析逻辑
1 | /** |
II. 其他
0. 项目
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840
3. 扫描关注
一灰灰blog
知识星球