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

多态本身不直接切换数据源,但它为多租户数据源切换提供了关键的抽象能力——通过统一接口+不同实现,把“选哪个库”这件事从业务代码里摘出来,让系统能根据租户类型自动匹配对应的数据源策略。
用接口定义租户类型识别契约
不要在 service 层写 if-else 判断租户是 saas 还是私有化客户,而是定义一个标准接口:
-
TenantTypeResolver 接口只声明
resolve(String tenantId)方法,返回枚举如TenantType.SAAS或TenantType.PRIVATE - 提供多个实现类:
SaasTenantResolver(查配置中心)、PrivateTenantResolver(查本地数据库)、TestTenantResolver(测试用固定返回) - Spring 自动注入具体实现,业务代码只依赖接口,完全不知道背后是哪种租户
让数据源路由器具备多态决策能力
数据源选择逻辑不是硬编码,而是由租户类型驱动的可插拔策略:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
TenantDataSourceRouter 接口定义
resolveDataSourceKey(String tenantId) -
SaasRouter实现:返回"ds_" + tenantId(对应独立数据库) -
PrivateRouter实现:返回"schema_" + tenantId(对应共享库+独立 schema) - 在
determineCurrentLookupKey()中调用tenantTypeResolver.resolve(tenantId),再委托给对应 Router,完成类型到数据源 key 的映射
结合 AbstractRoutingDataSource 完成运行时绑定
多态在这里落地为实际的数据源切换动作:
- 继承
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和校验逻辑,非法租户直接拦截 - 业务方法签名干净,不暴露任何数据源或租户类型细节
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










