有心栽花花不开,无心插柳柳成荫
致messageMVC
消息解耦
为什么消息可以解耦
消息解耦,重点有二
- 消息发送者与接收者互相不知道对方,也不可以假设对方
- 消息的发送与接收,并不需要同时在线,可以同时在线,也可以一方在线,也不应该假设互相在线
基于消息的这些特点,我们进行消息模型的设计时,不应该有任何假设。
但现实中的消息是,服务器(xxxMQ)必须在线,如果没有服务器,则收发双方必须在线,否则通讯必然失败。
所以我们在设计与现实是一种悖论,但偏偏是坚持了这种悖论,才能真正的做到消息解耦,否则就是缘木求鱼。
现实与设计的结合
在我们设计里,有三种方式
- 向消息队列服务器投递消息,从消息队列服务器接收消息,收发两端在时间与空间都是解耦的
- 向远端消息处理服务器(我们的应用服务)发送消息,远方未接受无返回,消息发送失败,消息处理服务器接受并返回结果,消息处理成功。消息发送端在线等待处理结果。
- 向本地服务(相同进程)发送消息,通过内部消息处理器处理并返回结果。
方式2/3除通讯方式不同,均采用了MessageProcessor类进行了虚拟化处理,收发双方的关联由它连接,互相在设计与开发时无需假设对方的实现方式,仅需约定相同的消息格式即可。
消息契约
为了保证消息处理的正确性,我们的消息是契约(Contract)耦合的,即文档是耦合。收发双方的消息格式必须提前约定,任何约定外的内容的发送与处理结果都是不可预知的。
- 离线调用,约定外的内容会被反序列化对象丢弃或产生异常。
- 在线调用,必须遵循对象继承且不应该依赖处理方法,派生内容会被丢弃(virtual属性实现例外,因为使用了相同属性名称)
- 消息的无文档处理,比如说日志分析,通过日志文本格式进行处理,其实也是一种契约,即输出格式可归类。
消息的运行时连接
- 消息发送,通过MessagePoster代理模式,虚拟化与调用方的联系,从而保证消息生产者与消息发送者的解耦,即互相不知道对方的存在
- 消息接收,MessageReceiver对象接受并还原消息内容,委托给MessageProcessor 对象进行处理并接受处理结果,它不知道也不应该知道处理对象的存在(ApiAcction运行时注册到服务对象,是为了实现查找表,不应该被接收者分析与处理)
- 消息调度,通过IMessageMiddleware虚拟化,MessageProcessor处理消息时才与之建立关系,运行前不应该互相伤害。
- 消息执行,ApiExecuter与ApiDiscory是消息处理的粘合剂, ApiDiscory发现api时还原消息契约(服务,方法,参数,返回值)后动态生成代码,供ApiExecuter运行时调用。ApiExecuter 查找ApiAction,还原参数后调用它并获取结果。运行前,互相并不认识,运行时动态配对,对上眼了,直接畅谈人生……
以上所述,上下游均相互解耦,开发时依据契约文档独立开发,运行时通过依赖注入方式组合,从而实现最大化的解耦与重用。
资产重用
相同的消息契约的不同实现,应该独立打包,可以在项目选用时重用。
驱动重用
同类设备驱动的应用目标是相同的,我们应该定义互相兼容的消息契约,独立开发与打包,在选用或替换时更换包即可使用。
流程控制重用
我们的设备的功能是明确的,显示内容也是明确的,任何第三方平台的调用,都应该转换为相同数据。
但不同第三方平台,操作的前置条件与后置流程并不完全符合我们的预定流程,所以我们应该根据不同的第三方平台,制定不同的流程控制规则,驱动界面的显示与操作,以保证界面元件的通用性。
当我们接入相同流程平台时,应该重用。
数据操作重用
与流程规则重用描述相同的第三方接口,应尽可能的重用。通过开发组件的复用,尽量减少重复造轮子。
一个可以描述的例子就是,读取订单接口相同,可以重用。
对于比较成熟的第三方平台,甚至可以通过配置文件进行重用。
单机模式与服务器模式双兼容,实现动态更新
单机在网络流畅情况,从服务器下载全部包(无人操作时自动重启),在发现网络不流畅时(通过健康检查),自动切换到本地模式(进程隧道调用),从而实现脱机联机均可正常运行。
健康检查
服务器与客户机,互相健康检查
- 客户机发现服务器无法连接时,自动降级为单机模式。重连后恢复联机模式。
- 服务器发现客户机工作不正常,如无法连接,设备异常日志,操作异常日志等情况,自动报警,保证第一时间进入维护状态。