安全审计框架通过抽象方法强制子类重写日志记录,以编译期契约保障“记什么、何时记、怎么记”;基类声明protected abstract logdataoperation()等方法锁定签名与语义,模板方法auditandexecute()固化校验→上下文捕获→日志生成→异步落库→异常兜底流程,钩子方法onauditsubmitted()支持可选扩展,规避构造器调用抽象方法导致的npe风险。

在安全审计框架中,用抽象方法强制子类重写操作日志记录,核心是把“记什么、何时记、怎么记”拆解为不可绕过的契约——不是靠文档提醒或人工检查,而是让编译器或解释器在代码写完那一刻就拦住遗漏。
定义抽象日志行为,明确审计责任边界
在基类中声明抽象方法,代表每个具体审计场景都必须回答“这条操作该怎么记录”。它不提供实现,只锁定签名和语义:
- 方法名要有业务含义,比如 logDataOperation() 或 buildAuditEntry()
- 参数需覆盖关键上下文:操作类型(INSERT/UPDATE/DELETE/SELECT)、影响行数、执行人、原始SQL、绑定参数等
- 返回类型建议为统一的 AuditEntry 对象,便于后续统一落库或脱敏处理
- 不能是 private / static / final;推荐 protected abstract(内部流程调用)或 public abstract(供框架调度)
嵌入模板方法,固化审计主干流程
光有抽象方法只能卡住“有没有写”,真正保障审计完整性,得靠模板方法把“校验权限→捕获上下文→生成日志→异步持久化→异常兜底”这些不变环节锁死:
- 主入口方法设为 final,例如 auditAndExecute(),子类无法篡改顺序
- 其中调用 logDataOperation() 这个抽象方法,作为唯一可变插槽
- 前置做租户隔离校验、后置加异步发送失败重试,子类不用重复写
- 这样既保证每条操作必经审计流程,又让不同数据源(MySQL/Oracle/Mongo)只需专注自己那部分日志组装逻辑
搭配钩子方法,支持审计策略差异化
不是所有审计动作都强制,有些是可选增强。比如敏感字段脱敏、关联审批单号、触发风控告警——这些用空的钩子方法开放:
- 声明 protected void onAuditSubmitted(AuditEntry entry) { }
- 子类按需重写,不重写也不影响编译和主流程
- 命名带 onXXX 或 afterXXX 前缀,一眼看出是扩展点而非契约义务
- 避免把“可选”塞进抽象方法里,否则会逼迫所有子类写空实现,破坏契约清晰性
避开初始化陷阱,确保日志上下文可用
审计日志依赖用户身份、请求ID、时间戳等上下文,而这些常在子类构造后才注入。因此要特别注意:
- 绝对不要在抽象基类构造器里调用抽象方法,此时子类字段为空,容易 NPE
- 日志方法应在业务执行时被模板方法调用,此时 Spring 上下文、ThreadLocal 用户信息均已就位
- 若需预加载配置(如审计开关、脱敏规则),放在 @PostConstruct 或 init() 方法中更安全
- MyBatis Interceptor 场景下,确保拦截器拿到的是完整 MappedStatement 和参数对象,而非未解析的占位符











