引言
在数据集成平台的开发过程中,我们经常会遇到这样的场景:某个功能的配置项非常多,涉及多个维度的选择,而且这些配置项之间存在依赖关系。比如配置主表与维表的JOIN关系时,需要先选择数据源,再选择目标表,最后设置匹配条件和输出列。如果把所有配置项都堆在一个页面上,不仅用户体验差,而且代码维护困难。
传统的单页面配置方式存在明显的局限性:配置项过多导致页面臃肿、用户容易迷失在复杂的表单中、配置步骤的逻辑关系不清晰。更重要的是,当需要新增类似的复杂配置功能时,往往需要重复大量的开发工作。
TIS(Table Integration System)通过设计一套通用的多步配置插件架构,优雅地解决了这个问题。这套架构不仅让复杂配置变得简单易用,更重要的是,它具有极强的扩展性——新增一个多步配置功能,只需要实现几个接口,编写少量代码即可完成。本文将深入剖析这套架构的设计原理,帮助开发者理解如何构建一个既灵活又易于扩展的配置系统。
多步配置插件的核心架构
整体架构设计
TIS的多步配置插件架构采用了前后端分离的设计思想,通过清晰的接口定义和配置驱动的方式,实现了高度的解耦和可扩展性。
【图片位置1:多步配置插件整体架构图】 说明:展示前端(Angular组件)、后端(Java插件接口)、配置文件(JSON)三者之间的关系,以及数据流转的方向
整个架构可以分为三个核心层次:
- 插件宿主层:定义多步配置的容器,负责管理所有步骤
- 步骤实现层:每个步骤的具体配置逻辑
- 数据解析层:将前端提交的数据转换为后端对象
这三层通过接口进行交互,每一层都可以独立扩展,互不影响。
后端架构设计
后端架构的核心是一套精心设计的接口体系,它定义了多步配置的标准流程和扩展点。
MultiStepsSupportHost:多步配置的宿主
这是多步配置插件的顶层接口,任何需要支持多步配置的插件都需要实现这个接口。它的职责非常明确:
- 持有所有步骤的配置数据
- 提供步骤数据的访问接口
- 定义步骤的元数据(步骤数量、每步的描述等)
通过实现这个接口,一个普通的插件就具备了多步配置的能力。这种设计遵循了"组合优于继承"的原则,让多步配置成为一种可选的能力,而不是强制的约束。
OneStepOfMultiSteps:单步配置的抽象
每个配置步骤都是一个独立的插件,继承自OneStepOfMultiSteps抽象类。这个设计非常巧妙:
- 每个步骤都是独立的,有自己的配置项和验证逻辑
- 步骤之间通过接口方法进行数据传递
- 步骤可以访问前序步骤的配置数据,实现配置的级联
例如,在JOIN配置场景中,第一步选择数据源后,第二步就可以根据选择的数据源加载对应的表列表;第三步又可以根据前两步的选择,展示可用的列信息。这种设计让复杂的配置流程变得清晰可控。
ElementCreatorFactory:数据解析的工厂模式
当用户在前端填写了复杂的表单数据(比如多个匹配条件、多个过滤规则),这些数据需要被解析成后端的Java对象。ElementCreatorFactory就是专门负责这个转换过程的工厂类。
它的设计体现了几个关键思想:
- 职责单一:每种数据类型对应一个Factory,只负责解析自己的数据
- 配置驱动:通过JSON配置文件指定使用哪个Factory,无需修改代码
- 验证集成:在解析过程中同步进行数据验证,及时反馈错误
更重要的是,Factory还负责向前端提供元数据,比如下拉框的选项、字段的约束条件等。这种双向的数据交互机制,让前后端的协作变得非常流畅。
ViewContent:前后端视图类型的桥梁
ViewContent是一个枚举类型,它定义了所有支持的视图类型。每种视图类型对应一种特定的数据结构和UI组件。
这个设计看似简单,实则非常关键:
- 它是前后端约定的"协议",双方通过ViewContent来识别数据类型
- 新增一种视图类型,只需要在枚举中添加一个值
- 前后端可以独立开发,只要遵循ViewContent的约定即可
【图片位置2:前后端数据流转示意图】 说明:展示用户操作 → 前端组件 → ViewContent映射 → ElementCreatorFactory解析 → 后端对象的完整流程
前端架构设计
前端架构同样遵循了组件化和类型驱动的设计原则。
TuplesPropertyType:视图类型的注册机制
TuplesPropertyType是前端对应ViewContent的枚举类型。当后端返回配置数据时,会携带ViewContent信息,前端通过TuplesPropertyType进行映射,决定使用哪个组件来渲染。
这种类型注册机制的优势在于:
- 新增视图类型时,只需要在switch语句中添加一个case分支
- 每个组件都是独立的,可以单独开发和测试
- 类型安全,编译期就能发现错误
组件化的步骤UI
每个配置步骤对应一个Angular组件,这些组件都继承自BasicTuplesViewComponent基类。基类提供了通用的功能:
- 数据绑定和验证
- 错误信息展示
- 与父组件的通信
具体的步骤组件只需要关注自己的业务逻辑,比如渲染表单、处理用户交互等。这种设计让组件的复用性非常高。
数据双向绑定与验证
前端使用Angular的双向绑定机制,用户的每次输入都会实时同步到数据模型中。当用户提交配置时,前端会将数据序列化为JSON格式,发送给后端。
验证逻辑分为两层:
- 前端验证:即时反馈,提升用户体验
- 后端验证:保证数据安全,防止恶意提交
后端验证失败时,错误信息会通过统一的格式返回给前端,前端根据字段路径将错误信息显示在对应的表单项旁边。
架构的扩展性设计
这套架构最大的价值在于它的扩展性。当需要新增一个多步配置功能时,开发工作量非常小,这得益于几个关键的设计决策。
接口抽象的威力
通过定义清晰的接口,架构将"做什么"和"怎么做"完全分离。
以JOIN配置为例,当我们需要新增"过滤条件"功能时,只需要:
- 创建一个新的数据类TableJoinFilterCondition,实现IMultiElement接口
- 创建对应的Factory类,实现ElementCreatorFactory接口
- 在ViewContent枚举中添加一个新值
这三步完成后,后端的扩展就完成了。整个过程不需要修改任何现有代码,完全符合"开闭原则"——对扩展开放,对修改关闭。
接口抽象的另一个好处是,它强制开发者思考功能的本质。比如ElementCreatorFactory接口定义了几个关键方法:
- parsePostMCols:解析前端提交的数据
- appendExternalJsonProp:向前端提供元数据
- getViewContentType:返回视图类型
任何需要解析复杂表单数据的场景,都可以套用这个模式。开发者不需要重新设计数据流转的逻辑,只需要实现这几个方法即可。
配置驱动的灵活性
JSON配置文件在这套架构中扮演了"粘合剂"的角色。它连接了Java字段和ElementCreatorFactory,让两者可以独立变化。
配置文件的结构非常简洁:
{
"字段名": {
"label": "显示标签",
"elementCreator": "Factory类的全限定名",
"enum": "获取初始数据的方法",
"viewtype": "视图类型",
"help": "帮助文本"
}
}
这种配置驱动的设计带来了几个好处:
- 热插拔:修改配置文件即可改变行为,无需重新编译
- 可视化:配置文件清晰地展示了字段和Factory的对应关系
- 解耦:Java代码和Factory类之间没有直接依赖
更重要的是,这种设计让非开发人员也能理解系统的配置逻辑。当需要调整字段顺序、修改标签文本时,只需要编辑JSON文件即可。
组件化的可复用性
前端的组件化设计让UI的复用变得非常简单。
每个组件都是自包含的,它有自己的模板、样式和逻辑。当需要创建一个新的配置步骤时,可以参考现有组件的实现,快速搭建出新的UI。
组件之间通过标准的Input和Output进行通信:
- Input接收父组件传递的数据和配置
- Output向父组件发送事件和数据变更
这种标准化的通信方式,让组件可以像乐高积木一样自由组合。比如,一个下拉选择组件可以在多个不同的配置步骤中使用,只需要传入不同的选项数据即可。
Angular的依赖注入机制进一步增强了组件的可测试性。每个组件可以独立进行单元测试,不需要启动整个应用。
实际应用:主表与维表JOIN配置
让我们通过一个实际的应用场景,来看看这套架构是如何工作的。
JOIN配置的业务场景
在数据集成场景中,经常需要将主表和维表进行JOIN操作,以实现数据的宽表化。比如订单表需要关联用户表,获取用户的详细信息;商品表需要关联分类表,获取分类名称等。
这个配置过程涉及多个步骤:
- 选择维表的数据源(可能有多个数据库)
- 选择具体的维表
- 设置JOIN的匹配条件(主表的哪个字段等于维表的哪个字段)
- 设置过滤条件(可选,比如只关联有效的记录)
- 选择需要输出的列
- 配置缓存策略
如果用传统的单页面方式,这个表单会非常复杂。而使用多步配置插件,可以将这个过程分解为三个清晰的步骤。
【图片位置3:JOIN配置三步向导界面截图】 说明:展示三个步骤的界面,第一步选择数据源,第二步选择表,第三步配置匹配条件、过滤条件和输出列
三步配置的设计思路
第一步:选择数据源
这一步的职责非常明确:让用户从已配置的数据源中选择一个。实现上,创建一个JoinerSelectDataSource类,继承OneStepOfMultiSteps,定义一个dbName字段用于存储选择的数据源名称。
前端对应一个简单的下拉选择组件,选项从后端的数据源列表中获取。
第二步:选择目标表
这一步依赖第一步的选择结果。JoinerSelectTable类可以通过getOneStepOf方法获取第一步的配置,从而知道用户选择了哪个数据源,进而加载该数据源下的表列表。
这种步骤间的数据传递机制,让配置流程具有了"智能"——后续步骤可以根据前面的选择动态调整。
第三步:配置匹配条件和输出列
这是最复杂的一步,需要配置多个匹配条件、多个过滤条件,还要选择输出列。
JoinerSetMatchConditionAndCols类定义了多个字段:
- matchCondition:匹配条件列表
- filterConditions:过滤条件列表
- targetCols:输出列列表
- colPrefix:列名前缀
- cache:缓存配置
每个字段都通过@FormField注解标注,指定了字段类型、验证规则等。关键的是,matchCondition和filterConditions字段的类型是MULTI_SELECTABLE,表示这是一个复杂的多元组配置。
过滤条件功能的扩展实现
最初的JOIN配置只支持匹配条件,后来需要新增过滤条件功能。这个扩展过程完美展示了架构的灵活性。
后端扩展:
- 创建TableJoinFilterCondition类,定义5个字段:tableType(主表/维表)、columnName(列名)、operator(运算符)、valueType(值类型)、value(值)
- 创建TableJoinFilterConditionCreatorFactory类,实现数据解析逻辑,并提供运算符、值类型等元数据
- 在ViewContent枚举中添加TableJoinFilterCondition值
- 在JoinerSetMatchConditionAndCols类中添加filterConditions字段
- 在JSON配置文件中添加filterConditions的配置项
前端扩展:
- 创建TableJoinFilterConditionComponent组件,渲染过滤条件的表单
- 在TuplesPropertyType枚举中添加TableJoinFilterCondition值
- 在类型映射的switch语句中添加对应的case分支
- 在Angular模块中声明新组件
整个扩展过程,没有修改任何现有的代码,只是新增了文件和配置。这就是良好架构设计带来的红利。
技术优势总结
开发效率的显著提升
通过这套架构,新增一个多步配置功能的开发成本大幅降低。
传统方式下,开发一个复杂的配置功能可能需要:
- 设计数据库表结构
- 编写后端的CRUD接口
- 设计前端的表单布局
- 实现前后端的数据交互
- 编写验证逻辑
- 处理各种边界情况
整个过程可能需要几天甚至一周的时间。
而使用多步配置插件架构,开发者只需要:
- 定义数据模型(实现接口)
- 实现Factory类(套用模板)
- 编写前端组件(参考现有组件)
- 添加配置项(编辑JSON文件)
熟练的开发者可以在半天内完成一个新功能的开发。这种效率的提升,来自于架构的标准化和模板化。
用户体验的优化
向导式的配置流程,让用户不再面对复杂的表单,而是一步步地完成配置。每一步的目标都很明确,用户不会感到迷茫。
步骤之间的数据联动,让配置过程更加智能。比如选择了数据源后,表列表会自动加载;选择了表后,列信息会自动展示。用户不需要手动刷新或重新加载。
实时的验证反馈,让用户在填写过程中就能发现错误,而不是提交后才被告知配置有误。这种即时反馈大大提升了配置的成功率。
系统可维护性的增强
清晰的架构边界,让代码的职责非常明确。当需要修改某个功能时,开发者可以快速定位到对应的类和组件,不会影响其他功能。
接口驱动的设计,让系统具有很好的可测试性。每个接口的实现都可以独立测试,不需要启动整个系统。这让单元测试变得简单可行。
配置文件的使用,让系统的行为更加透明。运维人员可以通过查看配置文件,了解系统的配置逻辑,而不需要阅读代码。
扩展场景展望
这套多步配置插件架构的应用场景远不止JOIN配置。它可以应用于任何需要复杂配置的场景。
数据转换规则配置:数据同步过程中,经常需要对数据进行转换,比如字段映射、类型转换、格式化等。这些转换规则的配置可以分为多个步骤:选择源字段、选择转换函数、配置参数、预览结果。
复杂数据源配置:某些数据源的配置非常复杂,比如Kafka需要配置集群地址、Topic、消费组、序列化方式等。通过多步配置,可以将这些配置项分组,让用户逐步完成。
工作流编排配置:数据处理流程可能包含多个节点,每个节点有自己的配置。通过多步配置,可以让用户先定义流程结构,再逐个配置节点参数。
机器学习模型配置:训练一个机器学习模型需要配置数据源、特征工程、算法参数、评估指标等。这个过程天然适合用多步配置来实现。
这些场景的共同特点是:配置项多、步骤间有依赖、需要向导式的用户体验。只要符合这些特点,都可以使用这套架构来实现。
总结
TIS的多步配置插件架构,通过精心设计的接口体系、配置驱动的灵活机制、组件化的前端实现,构建了一个既强大又易于扩展的配置系统。
这套架构的核心思想可以总结为几点:
- 接口抽象:通过接口定义标准流程,让扩展变得简单
- 配置驱动:用配置文件连接各个组件,实现解耦
- 组件化:前后端都采用组件化设计,提高复用性
- 类型安全:通过枚举类型实现前后端的类型映射,减少错误
对于开发者来说,这套架构提供了一个很好的参考:当面对复杂的配置场景时,不要试图用一个大而全的表单来解决,而是应该思考如何将配置过程分解为多个步骤,如何设计接口让系统具有扩展性,如何通过配置来驱动行为。
良好的架构设计,不仅能提升开发效率,更能让系统具有持续演进的能力。TIS的多步配置插件架构,正是这样一个经过实践检验的优秀设计。
本文基于TIS(Table Integration System)开源项目的实际开发经验总结而成。TIS是一个企业级的数据集成平台,致力于为数据工程师提供高效、易用的数据同步和处理工具。