控制中心核心思想
直指目标:设计一个核心处理模块,统一管理业务流控、配置业务模块间的交互以及数据在各模块间的流向以及接口的对接方式
设计思想: 基于代理的流程控制,模块化、公共接口化
重大选择:
实现内容
1. 业务流程配置化
2. 项目生存周期和流程状态监控
3. 动态模块加载
4. 固定接口定义(继承协议(Interface))
5. 基于拦截器的业务管理
实现思路
1. 设计模式选型: 适配器模式 + 代理模式 + 门面模式
2. 实体关系选型: 低耦合隔离关系
3. 接入方式: Controller层级 “注解”定义service id
4. 配置文件: 配置Service ID 语义和模块类型、默认流程图
5. 前端对接: 门面对接,隔离业务与视图,将业务流控代码全部提取并隔离
6. 架构模式: Center模式,无调度器,公共接口
7. 异常处理和解决: 注解辅助打印,快速定位,系统异常catch并resolve
模式图
1. 控制中心负责过滤所有触发业务跳转的请求(每个请求以@Checkpoint 注解标识),由拦截器识别。
2. 模块只能提供标准的交互Api用来进行模块间通信,内部的流程不参与控制
3. 控制中心记录模块通信历史,并写入日志。在发生跳转时会进行权限校验
4. 模块间有时序问题,即某模块可能有前置模块,前置模块可能还包含自己的前置
5. 模块统一的数据单元: 项目code。
6. 结束模块: 具有结束项目性质的模块,但无法直接结束流程,需委托控制中心
模块A |
A – B 绿色 B – 终止 黑色
项目结束 |
控制中心 |
用户配置 |
|
配置数据库 |
模块B |
模块C(结束) |
实现原理
1. 项目在代码层级上不再区分项目,使用超类Project,即包含公共属性的基类。询价、竞价、招标等项目都以子类实现,数据库层级不变
2. 所有项目的公共属性,如code, type 会作为模块接口交互的重要数据
3. 触发项目状态变化、基础属性的变化以及入库,相关实现都在ControlCenter 内以适配器的方式实现(一个项目类别一个适配器)
4. 模块分为入口模块和出口模块, 入口一般为创建项目,出口一般为项目结束
5. 通知和存储相关的实现都于模块内部以回调的形式实现,相当于控制中心代理实现,实现代码位于模块内,触发流程控制器时执行
6. 控制中心提供唯一门面,但是只暴露主动触发接口,不暴露任何业务相关接口
业务耦合
流程控制模块存在巨大的业务耦合关系,当流程中穿插了一个可配置的模块后,后续的模块内容都会根据当前添加的模块发生一定的变化,因此,需要为每一个可配置的模块实现具体的业务代码,实现位置为后续的模块内对应新增模块的变化所配置的代码块。
所以,前置原则:
只有实现并包含了对该可选模块的全部支持,才能够将这个可选模块作为这些业务模块的前置模块。
由于状态控制包含了不可预料的可选模块的制约,所以有必要将所有的不可预料转变为可预料的。即,在每个主流程的后置位都进行考虑,为其创建特殊项目状态,如审核中,报名中,变更审核中,交给可选模块自行处理。一个模块生命周期结束后便不再操作其自身,而是交由下一个模块,根据上一个模块结束时遗留的状态进行相关的操作。于是,我们得出结论:
模块不需要自身去判断后置模块的具体情况,只需要考虑前置模块对自身的影响。所有后置模块都必须针对前置模块进行匹配和扩充。
传入接口和传出接口
业务模块的规范性非常重要,提供统一的接口便于维护,也可以更好的提升代码质量。
接口规范模式图如下:
配置中心
配置中心的UI实现,用于暴露于用户面前让用户进行流程查看和配置的入口。
详细设计
1. 模块加载扫描
使用Application事件,从Bean容器中取出所有ModuleDefine注解声明的业务模块
2. 模块调用链
请求——》 控制中心 ——》 模块onExit ——》 请求逻辑 ——》 下个模块onEnter
3. 前端处理
拦截带有控制中心信息的ajax请求,处理控制中心指令,完成跳转或者放行。
4. 模块代理
做公共操作,为模块的生存周期做统一调度