在构建面向本地垂直行业的 SaaS 平台(如服务数百家独立连锁宠物门店的中台)时,架构师面临的最大梦魇往往不是高并发,而是“无止境的个性化业务规则”与“绝对的数据安全隔离”。
一方面,每个宠物店老板都有自己独特的营销玩法。例如:A 店的规则是“充值 1000 元送 200,外加 2 次免费深度洗护”;B 店的规则是“仅限泰迪犬,洗护项目满 150 打 8 折”。如果在代码里硬编码这些逻辑,核心计算引擎将迅速膨胀为无法维护的“大泥球(Big Ball of Mud)”。
另一方面,作为一个多租户(Multi-tenant)系统,A 店的店长绝对不能因为系统 Bug 越权查询到 B 店的会员数据与商品库存。
本文深度拆解,我们如何运用 AST(抽象语法树)动态规则引擎 与 基于 ORM 拦截器的多租户物理隔离,打造一套极致解耦、绝对安全的行业 SaaS 基座。
一、 告别硬编码:引入 AST 构建动态“计价与营销”引擎
宠物店的充值、扣费、折扣等规则,具有极强的时间与条件敏感性。为了让业务运营人员能随时热更新规则而无需重启微服务,我们引入了基于 AST(抽象语法树) 的轻量级表达式引擎(以 AviatorScript 为核心)。
规则的 DSL 化与 JIT 预编译:
商家在后台配置的充值规则,被前端序列化为标准化的 DSL(领域特定语言)表达式。
例如,某店的洗护折扣逻辑被转化为:animal_type == 'DOG' && weight <= 10 && is_vip == true ? origin_price * 0.8 : origin_price。
为了压榨极致的算力性能,当规则保存落盘时,系统会执行即时编译(JIT),将这些字符串预编译为高效的 AST 字节码,并常驻于微服务节点的 JVM 内存池(Caffeine Cache)中。运行时的极速求值(Runtime Evaluation):
当收银端发起结账请求时,算价引擎提取对应租户(Tenant)绑定的 AST 规则树,注入包含当前宠物体重、品种、会员等级的请求上下文(Env),进行纯内存级别的毫秒级求值。
这种设计不仅将极其复杂的条件分支从 Java 核心代码中彻底抽离,更实现了针对不同宠物门店千人千面的“低代码(Low-Code)”动态调价能力。
二、 数据安全底线:透明化的多租户(Multi-tenancy)隔离拦截层
SaaS 架构最核心的安全红线是租户数据隔离。我们采用了“共享数据库,共享数据架构,逻辑隔离”(即在每张表添加 tenant_id 字段)的低成本高弹性模式。
但如果依赖开发人员在每一条 SQL 语句上手动拼接 WHERE tenant_id = ?,不仅极易遗漏酿成重大数据安全事故,更让业务代码充满了令人窒息的重复逻辑。
为了实现对开发者的绝对透明,我们在 MyBatis-Plus(或底层 JDBC 层)构建了全局租户拦截器(TenantLineInnerInterceptor)。
上下文透传: 网关在鉴权时,将 JWT Token 解析出的 Tenant_ID 挂载到 ThreadLocal 中,贯穿整个 HTTP 请求的生命周期。
AST SQL 语法树改写: 当业务层执行 select from t_pet_member 时,底层 ORM 拦截器会使用 JSqlParser 解析原始 SQL 语法树,自动且强制地在 WHERE 条件中拼接租户过滤条件。最终发往 MySQL 的语句自动变成了 select from t_pet_member where tenant_id = '1001'。
防腐与忽略机制: 对于极少数需要跨租户操作的系统级定时任务,我们通过自定义注解 @IgnoreTenant 动态绕过拦截器。
这种将租户隔离逻辑下沉至数据库交互底层的设计,实现了业务代码的零侵入,从根源上杜绝了跨店数据越权泄露的灾难。
【架构思想沉淀】
构建优秀的 SaaS 底座,是与业务复杂度的长期博弈。通过 AST 引擎将“代码”抽象为“可配置的数据”,赋予了宠物门店极高的商业敏捷性;通过底层 SQL 语法树改写实现透明化的多租户隔离,守住了系统的数据生命线。这种深入骨髓的解耦与内聚,是传统单体应用迈向现代云原生 SaaS 中台的核心路径。
关于作者与团队:青海青帝科技技术研发中心长期致力于云原生多租户底层治理、AST 动态算价规则引擎、SaaS 数据隔离架构及垂直零售私有中台的工程实践落地。期待与技术同仁深入探讨交流。