一、业务扩展点设计
首先,通常当我们提到代码重构和优化的时候,都会说到可扩展性的代码实现,其实背后的潜台词,就是想要解决业务场景引入的复杂业务逻辑和多变的业务需求,就要考虑代码的可扩展性。
一提到可扩展性的代码,都会想到基于 Strategy Pattern 的扩展。策略模式的引入,主要有两个问题:
- 策略模式抽象了各种实现策略,但是需要 case by case 的分析,并不能提炼成一个通用的组件固化到框架中来。
- 各种策略的实现,反馈到代码侧的割裂感很严重,对于策略的测试也不是很友好
我们这里业务扩展点的设计思想并没有采用 Strategy Pattern ,而是引入了 COLA 的扩展点组件。业务扩展点,主要关键点有两个:业务身份识别能力和抽象的扩展点机制。
1.1. 业务场景身份识别
先来看看什么是业务身份识别,业务身份识别在我们的应用中非常重要,作为基础服务的各个应用,比如客户中心,素材中心,本身就要支撑类似商城、营销、CRM 等多个上层业务服务。
另外,作为一个 SaaS 平台系统,对于每个业务服务都天然存在多租户的概念。举个例子,对于 CRM 业务的线索导入来说,越秀地产和理财通是不同的租户,导入的规则不相同,那么它就是不同的业务方,所以传统的基于多租户(TenantId)的业务身份识别,是不能满足业务上多变的要求的,在此基础上我们引入了业务码(BizCode)来标识业务。
这样一来,我们的业务身份实际上是(BizCode,TenantId)二元组。在每一个业务身份下面,又可以有多个扩展点(ExtensionPoint),所以每一个扩展点的实现(Extension),实际上是一个三维空间中的向量。
类似于 Maven Coordinate 的概念,就是一个扩展坐标的概念(Extension Coordinate),这个坐标可以用(ExtensionPoint,BizCode,TenantId)来唯一标识。
有了业务身份这个关键抽象之后,通过身份来获取扩展实现的过程就变得水到渠成了,具体流程如下:
看起来这个思路是可行的,去除掉租户的概念,简化后的扩展点定位的方法如下图:然而,在实际业务需求中,除了需要支撑多个业务,很多时候还需要对同一种业务下不同的用例的差异化支持,更甚者,是对同一个用例不同场景的差异化支持。
前者比如营销业务中的“创建员工活码”和“创建识客码”两个用例,对于标签选择组件的筛选逻辑是有差异的。
又比如“创建素材”和“更新素材”是两个用例,但是大部分的业务代码是可以复用的,只有一小部分需要差异化处理。
后者比如,营销业务中的“创建员工活码”这个用例中,活码的“使用员工”是“只有自己”和“不仅仅只是自己”两种场景,在对于标签选择组件中,标签的筛选逻辑就是不同的。
- 创建员工活码场景,分管用户,活码的员工是自己,看到的是“所有企业标签”+“我作为管理范围内的员工,所在的管理组,管理的业务标签”
- 创建员工活码场景,分管用户,活码的员工不仅仅是自己,看到的是“所有企业标签”+“我作为管理员,所在的管理组,管理的业务标签”
再深入剖析一下,“标签选择组件中,在不同的业务场景下,不同的使用用户,应该展示什么样的标签数据” 这个复杂的业务场景。
先来看看产品对于规则的细化:
为了支持这种更细粒度的业务扩展,仅仅只依靠之前的“业务身份(BizCode)”是不够的,这里需要引入 Use Case 和 Scenario 两个新的概念。
1.2 业务扩展点概念
1.2.1. 业务 (Business)
对于大型公司来说,业务通常是一个业务线主体,比如 tmall、淘宝和菜鸟就是三个不同的业务。
对于我们来说,营销、商城、CRM、素材就是四个不同的业务。
1.2.2. 用例 (Use Case)
在软件工程中,每个用例提供了一个或多个场景,该场景说明了系统是如何和最终用户或其它系统互动,也就是谁可以用系统做什么,从而获得一个明确的业务目标。
创建标签、打标签等,都是标签系统的典型用例。
1.2.3. 场景 (Scenario)
场景实际上就是用例的实例(Instance),包括用例所有的可能情况(正常的和异常的)。
比如对于“创建标签”这个用例,就有“创建企业标签”,“创建自动标签”,“创建业务标签”等多个场景。
再比如“标签选择器”这个用例,有“营销域-创建员工活码-活码员工选择自己”,“营销域-创建员工活码-活码员工选择包含他人”
1.2.4. 业务 VS 用例 VS 场景
简单来说,就是一个业务是由多个用例组成的,一个用例是由多个场景组成的。
比如上面说的标签选择器这个扩展点
1.3. 扩展点实现思路
引入“用例”+“场景” 的概念后,扩展框架就从原来只能支持到“业务身份”的扩展,现在可以支持到“业务身份”,“用例”,“场景”的三级扩展,无疑比以前要灵活的多,并且在表达和可理解性上也比以前好。理论上就可以满足我们当下的业务复杂度需求了。引入新概念后,扩展定位的方式如下图:
在新的扩展框架下,实现上图中所展示的扩展:在 marketing 这个业务下——的创建员工活码用例——的使用员工只是自己场景——的标签筛选组件进行扩展,我们只需要声明一个如下的扩展实现(Extension)就可以了。
基于 Business+Use Case+Scenario 实现的业务扩展点:
营销+创建员工活码+自己
Or 营销+创建员工活码+不仅仅是自己
二、扩展点解决了标签服务什么问题
1.不同展示规则的标签聚合到同一个接口,完成接口收敛
2.业务灵活编排,实现不同业务需求
eg1:新增企业标签需要执行 校验、转换、加密、入库、同步外部系统、通知二方系统
而群标签仅需要执行 校验、转换、入库、通知二方系统
eg2: 在开发企业标签数据迁移job时, 单独抽出 转换 和 入库逻辑执行,实现代码复用。
三、扩展点使用方式
1.定义扩展点
定义接口继承 ExtensionPointI,接口中定义要扩展的方法。
2.实现扩展点
实现扩展点接口,加上注解 @Extension,指定注解的坐标(bizId,useCase,scenario)
3.通过扩展点执行器执行扩展点
注入ExtensionExecutor ,执行execute 或 executVoid 方法,传入扩展点, 业务坐标 和 扩展方法
四、扩展点原理
1. 设计原理
1.1 定义与注册扩展点
服务启动时,找到所有带有 @Extension 注解的类实例,提取注解中的坐标,注册到 本地的MAP中。
1 | package com.alibaba.cola.extension; |
1.2 执行器执行扩展点
使用框架中的执行器(ExtensionExecutor)执行,从本地MAP中取到扩展点执行业务方法
作者: 绵羊