不能直接用 static 存公共策略,因为 static 字段无法支持租户差异化、热更新和生命周期对齐;正确做法是用 static 作轻量引导入口,策略实体交由可管理缓存(如 @Cacheable 或 Redis)托管。
在多租户 SaaS 系统中,static 关键字本身不适用于缓存“租户公共基础策略”——因为这类策略虽是全局共享的,但必须支持动态更新、多租户差异化加载、运行时热刷新,而 Java 的 static 字段一旦初始化就长期驻留 JVM,无法感知配置变更,也不具备租户上下文感知能力。
公共基础策略(如默认审批流规则、通用字段校验逻辑、租户开通时的初始权限模板)看似“全局”,实则需满足三个关键约束:
而 static final Map<String, Policy> 或 static Policy DEFAULT_POLICY 类型的声明,既无法区分租户,也无法响应外部变更,强行使用会导致策略僵化、灰度失败、回滚困难。
应将 static 限定为**轻量级、无状态、只读的引导层**,把真正策略数据交给有生命周期管理能力的组件:
public static final PolicyLoader LOADER = new PolicyLoader(); —— 它本身不存策略,只提供 loadForTenant(String tenantId) 方法;Policy 对象)由 Spring @Cacheable(key = "#tenantId") 或 Guava Cache(带 refreshAfterWrite)托管,自动隔离租户、支持过期与刷新;仅当系统无配置中心、租户数<5、策略永不变更时,可谨慎使用 static 缓存,但须加防护:
static volatile Policy GLOBAL_DEFAULT + 双重检查同步块初始化,避免类加载阶段异常中断;setPolicy() 方法,所有变更必须走 reloadFromProperties() 并加锁;"[STATIC POLICY] Loaded at " + LocalDateTime.now(),便于故障时识别是否为陈旧缓存。生产环境更推荐将策略下沉至 Redis,利用前缀实现天然租户隔离:
saas:policy:default(全局默认)、saas:policy:tenant_abc123(租户定制);PolicyCache.get(tenantId),内部自动拼接前缀并 fallback 到 default;policy_updated:abc123 即主动清除对应 key,保证最终一致性。