多态通过统一接口与不同实现解耦租户识别与数据源路由——定义TenantTypeResolver接口及其实现类识别租户类型,再由TenantDataSourceRouter多态选择数据源key,结合AbstractRoutingDataSource和AOP自动注入租户上下文完成运行时切换。

多态本身不直接切换数据源,但它为多租户数据源切换提供了关键的抽象能力——通过统一接口+不同实现,把“选哪个库”这件事从业务代码里摘出来,让系统能根据租户类型自动匹配对应的数据源策略。
用接口定义租户类型识别契约
不要在 service 层写 if-else 判断租户是 saas 还是私有化客户,而是定义一个标准接口:
-
TenantTypeResolver 接口只声明
resolve(String tenantId)方法,返回枚举如TenantType.SAAS或TenantType.PRIVATE - 提供多个实现类:
SaasTenantResolver(查配置中心)、PrivateTenantResolver(查本地数据库)、TestTenantResolver(测试用固定返回) - Spring 自动注入具体实现,业务代码只依赖接口,完全不知道背后是哪种租户
让数据源路由器具备多态决策能力
数据源选择逻辑不是硬编码,而是由租户类型驱动的可插拔策略:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
TenantDataSourceRouter 接口定义
resolveDataSourceKey(String tenantId) -
SaasRouter实现:返回"ds_" + tenantId(对应独立数据库) -
PrivateRouter实现:返回"schema_" + tenantId(对应共享库+独立 schema) - 在
determineCurrentLookupKey()中调用tenantTypeResolver.resolve(tenantId),再委托给对应 Router,完成类型到数据源 key 的映射
结合 AbstractRoutingDataSource 完成运行时绑定
多态在这里落地为实际的数据源切换动作:
立即学习“Java免费学习笔记(深入)”;
- 继承
AbstractRoutingDataSource,重写determineCurrentLookupKey() - 方法内先从 ThreadLocal 或请求上下文拿到
tenantId - 再通过
TenantTypeResolver得到租户类型,交给对应TenantDataSourceRouter实现生成 key - 该 key 必须与
targetDataSources中注册的 key 完全一致(大小写、前缀都不能错) - 返回 null 会触发 Spring 找不到数据源异常,务必设默认兜底 key(如 "default")
用 AOP 统一注入租户上下文,屏蔽差异
避免每个 controller 都手动 setTenantId,用切面自动完成:
- 定义
@TenantContext注解,标注需要租户隔离的方法或类 - AOP 在执行前从 Header / JWT / 域名提取
tenantId,并调用TenantContext.set(tenantId) - 切面内部自动调用
TenantTypeResolver和校验逻辑,非法租户直接拦截 - 业务方法签名干净,不暴露任何数据源或租户类型细节

















